BeanPostProcessor
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(
Object bean, String beanName) throws BeansException;
BeanPostProcessor 接口定义bean初始化时的回调,我们可以实现自己的逻辑依赖解析等。我们可以自己实现该接口从而在spring的容器完成初始化配置也可以实现类似plugin的方式。我们可以定义多个类实现该接口,然后定义一下执行的优先级 spring文档中叫order,这样就会按我们设定的order执行你定义的多个类。
ApplicationContext 可以自动检测到任何实现了BeanPostProcessor接口的bean和注册这些bean作为post-processors。在bean创建的过程中调用。
在spring-beans module中有FactoryBeanTests这个类,找到第七个测试方法testFactoryBeansWithIntermediateFactoryBeanAutowiringFailure
@Test
public void testCircularReferenceWithPostProcessor() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(CIRCULAR_CONTEXT);
CountingPostProcessor counter = new CountingPostProcessor();
factory.addBeanPostProcessor(counter);
BeanImpl1 impl1 = factory.getBean(BeanImpl1.class);
assertNotNull(impl1);
assertNotNull(impl1.getImpl2());
assertNotNull(impl1.getImpl2());
assertSame(impl1, impl1.getImpl2().getImpl1());
assertEquals(1, counter.getCount("bean1"));
assertEquals(1, counter.getCount("bean2"));
}
该方法读取的是
CountingPostProcessor实现了BeanPostProcessor接口,我们在其中的两个方法中加上日志
public static class CountingPostProcessor implements BeanPostProcessor {
private final Map count = new HashMap();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("源码阅读debug postProcessBeforeInitialization:"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("源码阅读debug postProcessAfterInitialization:"+bean);
if (bean instanceof FactoryBean) {
return bean;
}
AtomicInteger c = count.get(beanName);
if (c == null) {
c = new AtomicInteger(0);
count.put(beanName, c);
}
c.incrementAndGet();
return bean;
}
public int getCount(String beanName) {
AtomicInteger c = count.get(beanName);
if (c != null) {
return c.intValue();
}
else {
return 0;
}
}
}
我们找到FactoryBeanTests-circular.xml查看其内容
其中的两个bean比较简单
public static class BeanImpl1 {
private BeanImpl2 impl2;
public BeanImpl2 getImpl2() {
return impl2;
}
public void setImpl2(BeanImpl2 impl2) {
this.impl2 = impl2;
}
}
public static class BeanImpl2 {
private BeanImpl1 impl1;
public BeanImpl1 getImpl1() {
return impl1;
}
public void setImpl1(BeanImpl1 impl1) {
this.impl1 = impl1;
}
}
但是注意这两个bean存在循环依赖关系 这个待会再说,先看CountingPostProcessor implements BeanPostProcessor
的两个方法的执行情况,跑一下junit测试 debug
在load的时候会解析xml并实例化bean 实例化得过程会调用到这两个方法
跑完看一下consle打印的日志
对了先说一下怎么开启spring源码的日志
其实很简单
# Set root logger level to Debug and its only appender to A1
log4j.rootLogger=ALL,A1
log4j.category.org.springframework=DEBUG
# A1 is set to be ConsoleAppender
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%t] - %m%n
其中log4j配置下一篇再补充一下
ALL是最小的 就是所有有关的日志都会打印,设置成ALL即可
还有一步要做就是加入编译环境
项目右键Build path
这样就可以打日志了
看一下刚刚debug输出的日志
2016-08-30 15:16:16 DEBUG [main] - Adding [systemProperties] PropertySource with lowest search precedence
2016-08-30 15:16:16 DEBUG [main] - Adding [systemEnvironment] PropertySource with lowest search precedence
2016-08-30 15:16:16 DEBUG [main] - Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]
2016-08-30 15:16:16 INFO [main] - Loading XML bean definitions from class path resource [org/springframework/beans/factory/FactoryBeanTests-circular.xml]
2016-08-30 15:16:16 DEBUG [main] - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
2016-08-30 15:16:16 DEBUG [main] - Loading schema mappings from [META-INF/spring.schemas]
2016-08-30 15:16:16 DEBUG [main] - Loaded schema mappings: {http://www.springframework.org/schema/beans/spring-beans-4.2.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsd, http://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd, http://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd, http://www.springframework.org/schema/util/spring-util-4.1.xsd=org/springframework/beans/factory/xml/spring-util-4.1.xsd, http://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd, http://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd, http://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool-4.1.xsd=org/springframework/beans/factory/xml/spring-tool-4.1.xsd, http://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd, http://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd, http://www.springframework.org/schema/beans/spring-beans-4.1.xsd=org/springframework/beans/factory/xml/spring-beans-4.1.xsd, http://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd, http://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd, http://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd, http://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd, http://www.springframework.org/schema/util/spring-util-4.0.xsd=org/springframework/beans/factory/xml/spring-util-4.0.xsd, http://www.springframework.org/schema/tool/spring-tool-4.0.xsd=org/springframework/beans/factory/xml/spring-tool-4.0.xsd, http://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-4.0.xsd=org/springframework/beans/factory/xml/spring-beans-4.0.xsd, http://www.springframework.org/schema/util/spring-util-4.2.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsd, http://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd, http://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-4.2.xsd, http://www.springframework.org/schema/tool/spring-tool-4.2.xsd=org/springframework/beans/factory/xml/spring-tool-4.2.xsd}
2016-08-30 15:16:16 DEBUG [main] - Found XML schema [http://www.springframework.org/schema/beans/spring-beans-3.0.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-3.0.xsd
2016-08-30 15:16:16 DEBUG [main] - Loading bean definitions
2016-08-30 15:16:27 DEBUG [main] - Creating shared instance of singleton bean 'bean1'
2016-08-30 15:16:27 DEBUG [main] - Creating instance of bean 'bean1'
2016-08-30 15:16:27 DEBUG [main] - Eagerly caching bean 'bean1' to allow for resolving potential circular references
源码阅读debug postProcessBeforeInitialization:org.springframework.beans.factory.FactoryBeanTests$PassThroughFactoryBean@659a969b
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$PassThroughFactoryBean@659a969b
2016-08-30 15:18:13 DEBUG [main] - Finished creating instance of bean 'bean1'
2016-08-30 15:18:13 DEBUG [main] - Creating shared instance of singleton bean 'beanImpl1'
2016-08-30 15:18:13 DEBUG [main] - Creating instance of bean 'beanImpl1'
2016-08-30 15:18:16 DEBUG [main] - Eagerly caching bean 'beanImpl1' to allow for resolving potential circular references
2016-08-30 15:18:16 DEBUG [main] - Creating shared instance of singleton bean 'bean2'
2016-08-30 15:18:16 DEBUG [main] - Creating instance of bean 'bean2'
2016-08-30 15:18:16 DEBUG [main] - Eagerly caching bean 'bean2' to allow for resolving potential circular references
源码阅读debug postProcessBeforeInitialization:org.springframework.beans.factory.FactoryBeanTests$PassThroughFactoryBean@49b0b76
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$PassThroughFactoryBean@49b0b76
2016-08-30 15:18:19 DEBUG [main] - Finished creating instance of bean 'bean2'
2016-08-30 15:18:19 DEBUG [main] - Creating shared instance of singleton bean 'beanImpl2'
2016-08-30 15:18:19 DEBUG [main] - Creating instance of bean 'beanImpl2'
2016-08-30 15:18:21 DEBUG [main] - Eagerly caching bean 'beanImpl2' to allow for resolving potential circular references
2016-08-30 15:18:21 DEBUG [main] - Returning cached instance of singleton bean 'bean1'
2016-08-30 15:18:21 DEBUG [main] - Returning eagerly cached instance of singleton bean 'beanImpl1' that is not fully initialized yet - a consequence of a circular reference
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl1@769f71a9
源码阅读debug postProcessBeforeInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl2@4c9f8c13
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl2@4c9f8c13
2016-08-30 15:18:23 DEBUG [main] - Finished creating instance of bean 'beanImpl2'
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl2@4c9f8c13
源码阅读debug postProcessBeforeInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl1@769f71a9
源码阅读debug postProcessAfterInitialization:org.springframework.beans.factory.FactoryBeanTests$BeanImpl1@769f71a9
2016-08-30 15:18:25 DEBUG [main] - Finished creating instance of bean 'beanImpl1'
2016-08-30 15:18:25 DEBUG [main] - Returning cached instance of singleton bean 'beanImpl1'
2016-08-30 15:18:25 DEBUG [main] - Returning cached instance of singleton bean 'bean1'
可以看到日志已经输出,其实仔细读日志基本的初始化过程也可以了解,
接下来看下spring怎么处理两个bean之间的循环依赖的。
其中日志中有几条这样的输出
Eagerly caching bean 'bean1' to allow for resolving potential circular references
2016-08-30 15:18:16 DEBUG [main] - Eagerly caching bean 'beanImpl1' to allow for resolving potential circular references
2016-08-30 15:18:21 DEBUG [main] - Eagerly caching bean 'beanImpl2' to allow for resolving potential circular references
2016-08-30 15:18:21 DEBUG [main] - Returning eagerly cached instance of singleton bean 'beanImpl1' that is not fully initialized yet
最后出现的这条日志其实就是 返回了之前的引用
找到输出这条日志的类AbstractBeanFactory的doGetBean方法 有isSingletonCurrentlyInCreation的判断
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
点进去找到源头是DefaultSingletonBeanRegistry
该类实现了spring-core中的接口 这个后续再分析,先看本类声明了需要存储的属性
/** Cache of singleton objects: bean name --> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(64);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map> singletonFactories = new HashMap>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map earlySingletonObjects = new HashMap(16);
/** Set of registered singletons, containing the bean names in registration order */
private final Set registeredSingletons = new LinkedHashSet(64);
/** Names of beans that are currently in creation */
private final Set singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap(16));
/** Names of beans currently excluded from in creation checks */
private final Set inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap(16));
/** List of suppressed Exceptions, available for associating related causes */
private Set suppressedExceptions;
/** Flag that indicates whether we're currently within destroySingletons */
private boolean singletonsCurrentlyInDestruction = false;
/** Disposable bean instances: bean name --> disposable instance */
private final Map disposableBeans = new LinkedHashMap();
/** Map between containing bean names: bean name --> Set of bean names that the bean contains */
private final Map> containedBeanMap = new ConcurrentHashMap>(16);
/** Map between dependent bean names: bean name --> Set of dependent bean names */
private final Map> dependentBeanMap = new ConcurrentHashMap>(64);
/** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */
private final Map> dependenciesForBeanMap = new ConcurrentHashMap>(64);
大概浏览下里面的方法
看到有对属性对象的remove和add等操作
其实
singletonFactories,用于存储在spring内部所使用的beanName->对象工厂的引用,一旦最终对象被创建(通过objectFactory.getObject()),此引用信息将删除
earlySingletonObjects,用于存储在创建Bean早期对创建的原始bean的一个引用,注意这里是原始bean,即使用工厂方法或构造方法创建出来的对象,一旦对象最终创建好,此引用信息将删除
最终创建完成bean后这两个对象中都不会存在bean 即size为0
debug发现为了完成最原始得bean注入意思是
bean1 注入的是最原始得bean2 (此时的bean2不包括属性bean1)
bean2注入的也是最原始得bean1(此时的bean1不包括属性bean2)
会放到cached
FactoryBeanRegistrySupport中
该类拥有属性
/** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
private final Map factoryBeanObjectCache = new ConcurrentHashMap(16);
两者的循环依赖是基于Setter的依赖注入
基于Setter的依赖注入,是在Bean完成实例化之后,容器调用Bean的setter方法来完成的。
这样的话就解决了循环依赖问题。