概述
Bean加载的总体流程
FactoryBean的使用
地位:FactoryBean接口是Spring重要的拓展接口
用途:用于复杂的初始化 或者 框架集成
使用:
自定义类继承接口FactoryBean
原理:spring的getBean方法会回调FactoryBean的getObject方法
缓存中获取单例bean
说明下3级缓存指的是什么:
map的名称 | 完整性 | 几级缓存 |
---|---|---|
singletonObjects | 完整的bean(就是我们最终使用的) | 第一级缓存 |
earlySingletonObjects | 半完整的bean(循环依赖时会出现) | 第二级缓存 |
singletonFactories | 工厂bean(使用FactoryBean接口会出现) | 第三级缓存 |
从3级缓存中获取bean,原则是第一级没有去第二级,第二级没有去第三极查找。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从第一级缓存中查找
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 从第二级缓存中查找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 加锁
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
// 加锁之后需要重新检查 第一级缓存、第二级缓存(保证多线程下的原子性)
if (singletonObject == null) {
// 从第三极缓存中查找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用工厂方法【1、工厂模式下会调用;2、循环依赖下会调用】
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
// 从singletonFactories中remove掉这个ObjectFactory
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
从bean的实例中获取对象
ObjectFactory 与 FactoryBean接口的比较
相同点:都有getObject方法
不同点:作用完全不相同。
ObjectFactory | FactoryBean | |
---|---|---|
相同点 | 有getObject方法 | 有getObject方法 |
不同点 | 用于“第三级缓存”,即singletonFactories | 1、用于复杂bean的初始化2、用于框架集成(如mybatis与spring) |
不同点体现的代码:
- ObjectFactory
AbstractAutowireCapableBeanFactory#doCreateBean方法的代码片段(功能:加入第三极缓存)
// 默认下每个bean都会进入这个方法
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
DefaultSingletonBeanRegistry#getSingleton方法代码片段(功能:查找3级缓存)
// 从第三极缓存中查找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用工厂方法【1、工厂模式下会调用;2、循环依赖下会调用】
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
// 从singletonFactories中remove掉这个ObjectFactory
this.singletonFactories.remove(beanName);
}
- FactoryBean
FactoryBean起作用的调用链路:
getBean —> AbstractBeanFactory#getObjectForBeanInstance —> FactoryBeanRegistrySupport#getObjectFromFactoryBean —> doGetObjectFromFactoryBean
// 代码片段
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
// 执行FactoryBean的getObject方法。
/**
* 注意:跟函数式接口ObjectFactory的定义非常相似(在getBean方法中出现,getObject的作用是定义模板方法中的特殊操作)
* [T getObject() throws BeansException;] 与 [T getObject() throws Exception;]
*/
Object object = factory.getObject();
return object;
}
获取单例
描述的DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)方法
1、检查缓存是否已经加载过
2、如没有加载,则记录beanName正在加载的状态
3、加载单例前记录加载状态
4、通过调用参数传入的ObjectFactory的getObject方法完成实例化bean
5、加载单例后的处理方法调用
6、将结果记录至缓存并删除加载bean过程中的所记录的各种辅助状态。
准备创建Bean
循环依赖
要理解spring是如何解决循环依赖的,我们需要先了解我们吧什么定义循环依赖。最简单的,bean1中有一个属性prop2,bean2中有一个属性prop1,prop2指向bean2,prop1指向bean1,这就是一个”最简单“的循环依赖的例子。
上面的例子太简单了,不能满足我们研究spring中3级缓存如何在循环依赖中的作用,所以,我们必须要把例子复杂起来一些。
测试环境准备
1、首先,我们把测试的代码贴出来
Bean_1.java、Bean_2.java、Bean_3.java文件:
@Data
public class Bean_1 {
private Bean_2 prop_2;
private Bean_3 prop_3;
}
@Data
public class Bean_2 {
private Bean_1 prop_1;
}
@Data
public class Bean_3 {
private Bean_1 prop_1;
}
application.xml文件:
<bean id="bean_1"
class="com.firefish.springsourcecodedeepanalysis.cycle.setter.Bean_1"
scope="singleton">
<property name="prop_2" ref="bean_2"></property>
<property name="prop_3" ref="bean_3"></property>
</bean>
<bean id="bean_2"
class="com.firefish.springsourcecodedeepanalysis.cycle.setter.Bean_2"
scope="singleton">
<property name="prop_1" ref="bean_1"></property>
</bean>
<bean id="bean_3"
class="com.firefish.springsourcecodedeepanalysis.cycle.setter.Bean_3"
scope="singleton">
<property name="prop_1" ref="bean_1"></property>
</bean>
Main.java文件:
public class Main {
public static void main(String[] args) {
XmlBeanFactory context = new XmlBeanFactory(new ClassPathResource("com/firefish/springsourcecodedeepanalysis/cycle/setter/application.xml"));
System.out.println(context.getBean("bean_3"));
}
}
2、然后,我们把bean的关系也贴出来
3、到这里其实我们就具备了研究3级缓存和循环依赖的条件了,只要运行Main.java。
bean生命周期中关于循环依赖的介绍
循环依赖的解决与bean的生命周期息息相关,我们不得不介绍下与循环依赖关联的一些点。
下面是bean生命周期与循环依赖关系密切的流程:
1、从3层级缓存中查找bean(getSingleton方法)
2、doCreateBean 之前记录"正在加载bean"(beforeSingletonCreation方法)
3、实例化bean(createBeanInstance方法调用构造器)
4、加入到第三级缓存(addSingletonFactory方法)
5、属性填充、初始化、后置处理器(重点是属性填充)
6、结束beanA的创建,移除bean的创建状态
画图演示存在循环依赖下,bean在3级缓存中的迁移过程
以上面的代码为实例,在循环依赖下,下面将用图片的形式展示bean_1、bean_2、bean_3在bean生命周期执行过程中如何通过3级缓存解决循环依赖问题。
1、从3层级缓冲中查找bean_3,发现找不到,则创建bean_3;先记录bean_3正在创建中的状态,实例化bean_3,把bean_3加入第三级缓存中
2、对bean_3进行属性填充,发现依赖prop_1,进而去创建bean_1
3、从3层级缓冲中查找bean_1,发现找不到,则创建bean_1;先记录bean_1正在创建中的状态,实例化bean_1,把bean_1加入第三级缓存中
4、对bean_1进行属性填充,发现依赖prop_2、prop_3;依据属性填充的先后顺序,先getBean_2,后getBean_3;进而就去创建bean_2
5、从3层级缓冲中查找bean_2,发现找不到,则创建bean_2;先记录bean_2正在创建中的状态,实例化bean_2,把bean_2加入第三级缓存中
6、对bean_2进行属性填充,发现依赖prop_1;进而去getBean_1
7、发现bean_1已经在创建中了,从3级缓冲的第三级缓存中可以找到bean_1了,调用bean_1的getObject方法(这里完成应用SmartInstantiationAwareBeanPostProcessor接口处理器来增强原始bean的功能。aop就是通过这个实现的)。从这里开始似乎开始循环依赖的结束了…。
8、把可能增强后的bean_1加入到第二级缓存中(为什么???),现在的情况如下图了。
9、目前为止,完成了bean_2的属性填充,然后它的初始化等等流程…,最后完成了bean_2的完整创建,它被移动到第一级缓存供用户使用。
10、接着步骤4,bean_1的属性prop_3还没有完成,现在进行bean3获取,即getBean_3
11、发现bean_3已经在创建中了,从3级缓冲的第三级缓存中可以找到bean_3了,调用了bean_3的getObject方法,状态如下了。
12、到这里,完成了bean_1的prop_2、prop_3的属性填充,以为着bean_1也就完整了创建,状态如下:
13、最后完整了bean_3的创建
过程的状态图都演示完了,下面总结下各种map的作用吧。(多debug几遍源码可能更好理解)
几种map的作用
-
singletonsCurrentlyInCreation(记录了那些bean正在创建中)
-
singletonObjects(完整的bean的缓存)
-
earlySingletonObjects
为什么需要earlySingletonObjects的缓存???
1、如果没有它,当多次依赖bean(如上文中的bean_1)将不得不从第三级缓存的getObject方法中重新创建新的bean,这就违反了”单例bean“;
2、对于这种中间状态的bean(如上文中的bean_1),总要有一个地方吧它缓存起来
总结:earlySingletonObjects的作用就是防止多次创建bean,也就是作为”半初始化“单例bean的一个中间缓存。
- singletonFactories
这个只有一个作用:应用 SmartInstantiationAwareBeanPostProcessor 接口完整bean的功能增强,如aop功能
总结
可以重点了解下循环依赖下,3个bean状态在3级缓存中的迁移情况,可以debug2遍看看;
了解后就不难理解这几种map的作用了。下面贴几张总结性的一些图,或许有用。
最后
以上就是斯文鸵鸟为你收集整理的说透 Spring循环依赖和3级缓存的全部内容,希望文章能够帮你解决说透 Spring循环依赖和3级缓存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复