您的位置:首页 > 移动开发 > Objective-C

bean的加载(九)记录创建bean的ObjectFactory

2016-07-12 12:54 621 查看
在doCreateBean中有这样一段代码:

//是否需要提早曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
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");
}
//为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
//依赖处理:在Spring中会有循环依赖的情况,例如,当A中含有B的属性,而B中又含有A的属性时就会
//构成一个循环依赖,此时如果A和B都是单例,那么在Spring中的处理方式就是当创建B的时候,涉及
//自动注入A的步骤时,并不是直接去再次创建A,而是通过放入缓存中的ObjectFactory来创建实例,
//这样就解决了循环依赖的问题。
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
//对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPostProcessor,
//其中我们熟知的AOP就是在这里将advice动态植入bean中,若没有则直接返回bean,不做任何处理
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

这段代码不是很复杂,但很难以让人理解这段代码的作用,而且这段代码从此函数中去理解和很难弄懂其含义,我们需要从全局的角度去考虑Spring的依赖解决办法。
earlySingletonExposure:从字面的意思理解就是提早曝光的单例,我们暂不定义它的学名叫什么,我们感兴趣的是有那些条件影响这个值。

mbd.isSingleton():没有太多可以理解的,此RootBeanDefinition代表的是否单例。

this.allowCircularReferences:是否允许循环依赖,很抱歉,并没有找到在配置文件中如何配置,但是在AbstractRefreshableApplicationContext中提供了设置函数,可以通过硬编码的方式进行设置或者可以通过自定义命名空间进行配置,其中硬编码方式代码如下:ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext("aspectTest.xml");
bf.setAllowBeanDefinitionOverriding(false);isSingletonCurrentlyInCreation(beanName):该bean是否在创建中。在Spring中,会有个专门的属性默认为DefaultSingletonBeanRegistry的singletonsCurrentlyInCreation来记录bean的加载状态,在bean开始创建前会将beanName记录在属性中,在bean创建结束后会将beanName移除。那么我们跟随代码一路走下来可以对这个属性的记录并没有多少印象,这个状态是在哪里记录的呢?不同scope的记录位置不一样,我们以singleton为例,在singleton下记录属性的函数是在DefaultSingletonBeanRegistry类的public
Object getSingleton(String beanName,ObjectFactory singletonFactory)函数的beforeSingletonCreation(beanName)和afterSingletonCreation(beanName)中,在这两段函数中分别this.singletonsCurrentlyInCreation.add(beanName)与this.singletonsCurrentlyInCreation.remove(beanName)来进行状态的记录与移除。

经过以上的分析我们了解变量earlySingletonExposure是否是单例,是否允许循环依赖,是否对应的bean正在创建的条件的综合。当这3个条件都满足时会执行addSingletonFfactory操作,那么加入SingletonFactory的作用是什么?又是在什么时候调用的?

我们还是以最简单AB循环为例,类A中含有属性B,而类B中又会含有属性A,那么初始化beanA的过程如下:



上图展示了创建BeanA的流程,在创建A的时候首先会记录类A所对应额beanName,并将beanA的创建工厂加入缓存中,而在对A的属性填充也就是调用pupulateBean方法的时候又会再一次的对B进行递归创建。同样的,因为在B中同样存在A属性,因此在实例化B的populateBean方法中又会再次地初始化B,也就是图形的最后,调用getBean(A).关键是在这里,我们之前分析过,在这个函数中并不是直接去实例化A,而是先去检测缓存中是否有已经创建好的对应的bean,或者是否已经创建的ObjectFactory,而此时对于A的ObjectFactory我们早已经创建,所以便不会再去向后执行,而是直接调用ObjectFactory去创建A.这里最关键的是ObjectFactory的实现。addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
//对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPostProcessor,
//其中我们熟知的AOP就是在这里将advice动态植入bean中,若没有则直接返回bean,不做任何处理
return getEarlyBeanReference(beanName, mbd, bean);
}
});

其中getEarlyBeanReference的代码如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}


在getEarlyBeanReference函数中除了后处理的调用外没有别的处理工作,根据分析,基本可以理清Spring处理循环依赖的解决办法,在B中创建依赖A时通过ObjectFactory提供的实例化方法来获取原始A,使B中持有的A仅仅是刚刚初始化并没有填充任何属性的A,而这初始化A的步骤还是刚刚创建A时进行的,但是因为A与B中的A所表示的属性地址是一样的所以在A中创建好的属性填充自然可以通过B中的A获取,这样就解决了循环依赖的问题。
下面一节我们一起分析关于populateBean这个函数是如何进行属性填充的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: