- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
5.7.2 记录创建 bean 的 ObjectFactory
在 doCreate 函数中有这样一段代码:
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 加入工厂
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
Processor,
//对 bean 再一次依赖引用,主要应用 SmartInstantiationAware BeanPost
bean,不做任何处理
//其中我们熟知的 AOP 就是在这里将 advice 动态织入 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.singletonsCurrentlyIn Creation.remove(beanName) 来进行状态的记录与移除。
经过以上分析我们了解变量 earlySingletonExposure 是否是单例、是否允许循环依赖、是否对应的 bean 正在创建的条件的综合。当这 3 个条件都满足时会执行 addSingletonFactory 操作,那么加入 SingletonFactory 的作用是什么呢?又是在什么时候调用呢?
我们还是以最简单 AB 循环依赖为例,类 A 中含有属性类 B,而类 B 中又会含有属性类 A,那么初始化 beanA 的过程如图 5-3 所示。
图 5-3 处理循环依赖
图 5-3 中展示了创建 beanA 的流程,图中我们看到,在创建 A 的时候首先会记录类 A 所对应的 beanName,并将 beanA 的创建工厂加入缓存中,而在对 A 的属性填充也就是调用 populate 方法的时候又会再一次的对 B 进行递归创建。同样的,因为在 B 中同样存在 A 属性,因此在实例化 B 的的 populate 方法中又会再次地初始化 B,也就是图形的最后,调用 getBean(A)。关键是在这里,有心的同学可以去找找这个代码的实现方式,我们之前已经讲过,在这个函数中并不是直接去实例化 A,而是先去检测缓存中是否有已经创建好的对应的 bean,或者是否已经创建好的 ObjectFactory,而此时对于 A 的 ObjectFactory 我们早已经创建,所以便不会再去向后执行,而是直接调用 ObjectFactory 去创建 A。这里最关键的是 ObjectFactory 的实现。
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
//对 bean 再一次依赖引用,主要应用 SmartInstantiationAware BeanPost
Processor,
bean,不做任何处理
//其中我们熟知的 AOP 就是在这里将 advice 动态织入 bean 中,若没有则直接返回
return getEarlyBeanReference(beanName, mbd, bean);
}
});
其中 getEarlyBeanReference 的代码如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object
bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBean PostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiation
AwareBeanPostProcessor) 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 获取,这样就解决了循环依赖的问题。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论