【Spring】Spring的循环依赖问题
1. Spring bean 的生命周期
1. java 对象和 spring bean 的区别
java
对象:只要被实例化的类,在堆上分配了内存
spring bean
: 是经过了完整的生命周期,存在于spring
容器中的对象
2. spring bean 生命周期流程
* 1. 实例化spring容器
* 2. 扫描符合spring bean规则的类,放到一个集合中
* 3. 遍历集合中的类 ==> 封装成一个beanDefinition对象,生成 beanDefinitionMap
* 4. 遍历beanDefinitionMap == beanDefinition对象
* 5. 解析并验证 beanDefinition
* 6. 通过 beanDefinition 得到class
* 7. 得到class的所有构造方法,并推断出合理的构造方法
* 8. 通过推断出来的构造方法,反射实例化一个对象
* 9. 合并 beanDefinition
* 10. 提前暴露一个工厂 ==> 循环依赖
* 11. 属性注入 ==> 判断是否需要完成属性填充
* 12. 执行aware接口(这个是分不同的aware接口分开执行的)
* 14. 执行spring的生命周期回调方法(这个分不同的生命周期回调方式分开执行的,有PostConstrut InitializingBean)
* 15. 完成代理aop
* 16. put到单例池中
3. 通过 spring bean 生命周期的几个步骤查看循环依赖
利用本地的代码调试,查看spring bean
的生命周期来看循环依赖是怎么完成的。首先创建两个被spring
管理的bean
,且让他们循环依赖.
@Component
public class X {
@Autowired
private Y y;
public X() { System.out.println("Create X"); }
}
@Component
public class Y {
@Autowired
private X x;
public Y() { System.out.println("Create Y"); }
}
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
}
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
// 下面的代码功能之一是:将配置类转化为 beanDefinition 对象存到 beanDefinitionMap 中
register(componentClasses);
refresh();
}
-
在
invokeBeanFactoryPostProcessors
函数中完成第三步的扫描生成beanDefinitionMap.
在demo
中的x
和y
对象再看下
beanDefinition
对象中包含的内容,其中包含一些我们常见的属性scope
,autowireMode
,abstructFlag
-
从
fin
ishBeanFactoryInitialization
完成bean
的实例化等过程,重点调试这块代码:3.1 在
finishBeanFactoryInitialization
【AbstractApplicationContext
】完成第8步对象的实例化,在finishBeanFactoryInitialization
中的preInstantiateSingletons
【DefaultListableBeanFactory
】方法中校验beanDefinition
:public void preInstantiateSingletons() throws BeansException { ... // 可以看到这里 spring 会把 beanDefinitionMap 中的所有的 bean 的名字存到一个 List 集合中 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 遍历 beanDefinitionMap 中的 beanDefinition for (String beanName : beanNames) { // 可以简单理解为从 `beanDefinitionMap` 中获取 `beanDefinition` RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 对beanDefinition 进行校验,校验是不是非抽象的,是不是单例的,是不是非懒加载的 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { ... } else { // 在这一步获取去创建对象 // 这一步有两个作用 1. 返回一个bean 2. 创建一个bean getBean(beanName); } } } ... }
3.2 进入
getBean(beanName)
【AbstractBeanFactory
】->doGetBean
【AbstractBeanFactory
】protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // 我们把视角放到我们自己的类 X 和 Y 上 // 获取x的bean, 现在可以理解为从单例池中获取x,显然第一次初始化创建 X 对象的时候,单例池中没有 X 的对象 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } // 如果没有bean就需要进入下面的代码创建出bean else { ... try { ... // Create bean instance. if (mbd.isSingleton()) { // 单例 bean 的生命周期中会走到这里 // 这里是个 lambda 表达式,getSingleton 的第二个参数是一个接口,这个接口中只有一个抽象方法,这里的意思就是实现那个抽象方法 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } ... }); ... } ... }
3.3 然后调用链
getBean(beanName)
【AbstractBeanFactory
】 ->doGetBean
【AbstractBeanFactory
】->getSingleton
:【DefaultSingletonBeanRegistry
】,进入getSingleton
:【DefaultSingletonBeanRegistry
】
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 获取尝试获取bean,此时显然没有 x 的bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
// 这一步会把正在创建的 beanName 放到一个集合中 `singletonsCurrentlyInCreation`
// 其中 Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 从集合的名字可以看出来:这个集合表示正在创建的单例bean的集合
// 执行完这句话之后 singletonsCurrentlyInCreation 有一个对象 x
beforeSingletonCreation(beanName);
...
try {
// 这里是上一步的 lambda 表达式,这个getObject 会走到上一步的 createBean(beanName, mbd, args) 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
...
}
return singletonObject;
}
}
3.4 调用链createBean(beanName, mbd, args)
【AbstractAutowireCapableBeanFactory
】 ->doCreateBean(beanName, mbdToUse, args)
【AbstractAutowireCapableBeanFactory
】,进入doCreateBean(beanName, mbdToUse, args)
【AbstractAutowireCapableBeanFactory
】
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
...
if (instanceWrapper == null) {
// 这一步中推断构造方法,并反射实例化对象, 此时反射生成的对象是x
// 最后实例化对象的代码为: ctor.newInstance(argsWithDefaultValues) [BeanUtils]
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 调用spring的后置处理器, 可以通过后置处理器来自定义bean ==> spring自己的后置处理器
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
...
}
}
// 这里判断是否提前暴露一个工厂,三个条件
// 1) 判读beanDefinition 是否是单例的
// 2) 判读spring是否支持循环依赖 ==> spring 默认是支持循环依赖的
// 3) 判读singletonsCurrentlyInCreation集合中是否存在当前的beanName ==> 在3.3 步中会将正在创建的x放到了这个集合中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
...
// 这一步就是提前暴露一个工厂,经过这一步之后
// singletonFactories 这个Map里面存了可以创建 x 的单例工厂singletonFactory
// earlySingletonObjects 这个Map为空
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 这一步完成属性注入,也就是自动注入。当前正在x的生命周期内,这时候要注入y
// 要注入y时,就要经过y的完整的生命周期
// 这就和x的生命周期经过的步骤是一致的
// 1. 将y加入到正在创建的beanName的集合singletonsCurrentlyInCreation中
// 2. 将y加入到提前暴露的工厂singletonFactories中
// 等到y的生命周期走到这里的时候,又要注入x
// 这时候按理说又要走进x的生命周期中,但是上一轮中,x的生命周期已经走了一半了,这是我们重新回到3.2中
populateBean(beanName, mbd, instanceWrapper);
// 这一步完成对象的创建,并将bean put到单例池中
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...
return exposedObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 可以看到这里有两个缓存,一个是earlySingletonObjects,一个是singletonFactories,两个缓存的数据结构如下:
// Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); ===> spring 的二级缓存
// Map<String, Object> earlySingletonObjects = new HashMap<>(16); ===> spring 的三级缓存
if (!this.singletonObjects.containsKey(beanName)) {
// 在二级缓存中存放一个能产生指定 bean 的 singletonFactory
// 这里为什么不直接存在一个bean,而是存放一个 singletonFactory 呢?
// 在 singletonFactory (也就是上面一个代码块中作为函数传过来的参数[getEarlyBeanReference])中可以看出,存工厂的目的是为了后续的扩展,可以在 // 工厂中对指定的bean做一个后置处理
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
3.5 当y
注入x
的时候,再次经过x
的生命周期过程,再次回到3.2中的步骤
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 这次我们重点看一下getSingleton(beanName) 这个方法里面到底是怎么获取bean的
// 注意DefaultSingletonBeanRegistry中有很多getSingleton 方法,注意重载,找到此时对应的getSingleton
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
...
}
3.6 调用链: getSingleton(beanName)
【DefaultSingletonBeanRegistry
】 -> getSingleton(beanName, true)
【DefaultSingletonBeanRegistry
】,进入getSingleton(beanName, true)
方法:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先从单例池中获取bean对象 ==> 单例池 singletonObjects 中存放的是已经经过了完整的生命周期的bean
// 显然当y注入x的时候,x还没有经过完整的生命周期,所以this.singletonObjects.get('x') == null;
// Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
Object singletonObject = this.singletonObjects.get(beanName);
// 第二个判读条件为 x 是否在正在创建的集合singletonsCurrentlyInCreation中,由3.3步可以知道,x在这个集合中,进入if条件
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 先从三级缓存中获取x的bean, 但是从之前的步骤中可以知道,spring并没有将x放到三级缓存earlySingletonObjects中
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 从二级缓存中获取x的bean, 从之前的步骤中可以知道,spring将x和y对放进了二级缓存 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 利用 x 提前暴露的工厂产生一个x的bean,但是这里的bean是没有经过完整的生命周期的半成品,比如里面需要注入的y还是null
singletonObject = singletonFactory.getObject();
// 最后将 x 从二级缓存中移除,加入到三级缓存中
// 那么为什么要将x从二级缓存中移除,加入到三级缓存中呢?
// 因为利用工厂产生bean, 可以对bean进行各种后置处理,但是这无疑增加了代码执行的成本,既然已经用提前暴露的工厂产生了一个bean,也就是经过 // 了一些过程了,下次就不需要再进行相同的操作了
// 说白了,二级缓存提升了bean的自定义操作,提高了可扩展性,三级缓存提高了效率
// 从二级缓存中remove是为了gc
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}