依赖注入(二)Spring Dependency injection
Spring核心功能之一是IOC容器,Spring凭借优雅的扩展性和强大的配置功能,几乎已经让它成为服务端IOC的标杆。也正因为Spring,才有了Guice等后起之秀。
IOC 容器
我们先从一个简单的例子开始,了解一下Spring IOC容器的用法,更多的用法可以参见Spring官方文档。
- 写一个服务接口
package com.deepoove.diexample.service;
public interface AccountService {
String get();
}
- 实现这个接口
package com.deepoove.diexample.service;
public class AccountServiceImpl implements AccountService {
@Override
public String get() {
return "Sayi";
}
}
- 使用XML形式配置服务的实例化
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="accountService" class="com.deepoove.diexample.service.AccountServiceImpl">
</bean>
</beans>
- 容器加载XML配置,负责Bean的创建,装配和销毁。
@Test
public void testXMLConifg() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
Assert.assertEquals(accountService.get(), "Sayi");
context.close();
}
通过这个简单的例子,我们看到ClassPathXmlApplicationContext起了重要的作用,它负责整个Bean的生命周期,我们不妨先看看这个类关系图:

暂时我们无需关注细节,只需要知道BeanFactory和ApplicationContext都是接口,它们是整个容器的核心。BeanFactory类似于上一篇提到的门面Injector,提供了统一的DI接口,ApplicationContext是它的子接口,包含了它所有功能之余,还提供了更多的特性,比如AOP。
BeanFactory or ApplicationContext? Use an ApplicationContext unless you have a good reason for not doing so.
Spring 依赖注入 与 JSR330
Spring提供了自己的注解外,也支持JSR330的注解。下表列出了它们类似的功能,当然Spring提供了等多的注解,比如@Service标识一个服务,@Component标识一个组件。
| Spring | JSR330 |
|---|---|
@Autowired |
@Inject |
@Scope("singleton") |
@Singleton |
@Qualifier |
@Qualifier / @Named |
| ObjectFactory<T> | Provider<T> |
源码分析
我们跟着ClassPathXmlApplicationContext来一步步探究下Spring DI的源码。
BeanFactory默认实现是DefaultListableBeanFactory,包含了存储所有Bean的数据结构。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
核心初始化代码在AbstractApplicationContext.refresh()方法,每行代码具体作用可以阅读英文注释来了解。ApplicationContext通过持有DefaultListableBeanFactory对象获得所有BeanFactory的功能。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
接下来会对几个核心步骤作一个说明。
obtainFreshBeanFactory()创建DefaultListableBeanFactory,加载BeanDefinition
obtainFreshBeanFactory()获得了具体BeanFactory的实例,是通过如下代码实现的。
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId()); // 设置唯一ID
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory); // 读取Bean的定义,可以是XML形式,也可以是其它形式
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
接下来我们说明下loadBeanDefinitions方法,它的主要作用是将Beans的定义加载到BeanFactory,初始化beanDefinitionMap。
/**
* Load bean definitions into the given bean factory, typically through
* delegating to one or more bean definition readers.
* @param beanFactory the bean factory to load bean definitions into
* @throws BeansException if parsing of the bean definitions failed
* @throws IOException if loading of bean definition files failed
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
Spring提供了统一的接口BeanDefinitionReader来加载Bean,比如实现类XmlBeanDefinitionReader从XML中读取Bean,Spring也实现了其它的读取器,AnnotatedBeanDefinitionReader从注解读取Bean,JdbcBeanDefinitionReader提供了利用SQL从数据库读取Bean的功能。
XmlBeanDefinitionReader主要通过委托类BeanDefinitionParserDelegate实现,具体如何加载的源码本文不作过多展开。
prepareBeanFactory(beanFactory) 对容器进行标准化配置
比如设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
设置ApplicationContextAwareProcessor支持对某些特殊组件(Aware)的注入(关于BeanPostProcessor参见下文);
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
注册一些默认的Bean。
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
invokeBeanFactoryPostProcessors(beanFactory) 调用BeanFactoryPostProcessors
Spring容器的扩展点BeanFactoryPostProcessors提供了在BeanDefinition已加载,还没有任何Bean被实例化的时候操作BeanFactory的能力。
registerBeanPostProcessors(beanFactory); 注册BeanPostProcessor
Spring容器的扩展点BeanPostProcessor提供了Bean在调用初始化方法(InitializingBean's {@code afterPropertiesSet或者init-method)前后操作Bean的能力。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor为Spring提供了优秀的扩展能力,AOP(AspectJAwareAdvisorAutoProxyCreator)和@Autowired(AutowiredAnnotationBeanPostProcessor)的特性都是基于此扩展的插件。

在业务开发中,经常需要在关键流程记录日志,代码可能会是这样:
Log logger = LogFactory.getLog(getClass());
我们可以实现BeanPostProcessor接口,在实例化Bean后通过反射获取到logger对象,进而实例化logger来避免频繁的写这串日志变量声明代码。
initApplicationEventMulticaster()初始化事件分发 和 registerListeners()注册监听器
默认广播实现是SimpleApplicationEventMulticaster类,Spring监听事件采用观察者模式,我们可以注册自己的Listener监听器,也可以自定义事件Event。
finishBeanFactoryInitialization(beanFactory) 实例化非Lazy的单例Bean
我们直接看核心代码AbstractAutowireCapableBeanFactory.doCreateBean方法,作用是创建Bean。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
其中earlySingletonExposure是为了解决循环依赖的问题,我们先把重点放到以下三行代码:
- instanceWrapper = createBeanInstance(beanName, mbd, args);用来创建具体对象实例
- populateBean(beanName, mbd, instanceWrapper);用来填充对象的属性
- initializeBean(beanName, exposedObject, mbd);调用初始化方法
createBeanInstance最核心的代码如下:
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
实现原理是通过反射获得构造器,然后创建实例。此处采用了策略模式,实例化对象的接口为InstantiationStrategy,两个实现类SimpleInstantiationStrategy和CglibSubclassingInstantiationStrategy(支持Method Injection)。
反射的代码就很简单了,在BeanUtils中提供了静态方法instantiateClass:
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
populateBean注入的核心代码在AbstractAutowireCapableBeanFactory.autowireByType,通过DefaultListableBeanFactory.resolveDependency解析依赖对象,PropertyDescriptor注入属性值。
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
关于Aware注入
在源码分析中,提到过ApplicationContextAwareProcessor类,它实现了BeanPostProcessor接口,在Bean调用初始化方法前,支持对一些实现了Aware接口的Bean的某些特定属性的注入。
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}

更多:扩展点FactoryBean
org.springframework.beans.factory.FactoryBean和BeanFactory只是两个单词的顺序不同,但它们绝对不是一样的东西。
factory-bean提供了通过工厂和工厂方法实例化Bean的xml配置方式。
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
org.springframework.beans.factory.FactoryBean为我们提供了生成Bean的工厂方式的接口。
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
getObject是具体实例化的Bean,getObjectType是Bean的类型,我们实现这个方法来实例化我们所需要的所有对象。 Spring很多地方使用了FactoryBean,比如ListFactoryBean、MapFactoryBean和spring-remoting模块:HttpInvokerProxyFactoryBean、HessianProxyFactoryBean,这里就不作过度延伸了。
循环依赖问题和@Lazy
Spring解决了单例下属性注入的循环依赖问题。对于构造器依赖,或者非单例情况下,可以使用@Lazy注解延迟实例化。
关于Spring循环依赖,这里有篇英文文章,写的很易懂。http://www.baeldung.com/circular-dependencies-in-spring
我们先来分析下原理,单例下属性注入在上文提到的核心三行代码已经看得很清楚,采取提前暴露对象+延迟注入属性的方式,先实例化所有单例实例,再对属性进行注入,对于prototype类型的实例,或者构造器循环依赖就会抛出BeanCurrentlyInCreationException异常。
@Lazy的核心原理是采取了动态代理的方式,当构造器依赖一个@Lazy修饰的Bean时,会优先返回这个Bean的动态代理,而将这个Bean的实际初始化工作延迟,Spring的代理的核心类是ProxyFactory,会在我的另一篇文章《面向切面编程AOP》中详细阐述。
解析@Lazy注解的入口在DefaultListableBeanFactory.resolveDependency,源码如下:
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
生成代理的方法源码如下:
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
if (target == null) {
Class<?> type = getTargetClass();
if (Map.class == type) {
return Collections.emptyMap();
}
else if (List.class == type) {
return Collections.emptyList();
}
else if (Set.class == type || Collection.class == type) {
return Collections.emptySet();
}
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
"Optional dependency not present for lazy injection point");
}
return target;
}
@Override
public void releaseTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
return pf.getProxy(beanFactory.getBeanClassLoader());
}
总结
至此,我们对Spring的容器和Bean的创建过程进行了源码分析,正因为Spring优秀的扩展机制,当我们了解这些机制后,可以为技术赋能,实现更高级的功能。
下一篇我们将重点解读google guice框架,它同样优秀,还轻量级,待续。