【Spring】Spring的循环依赖问题

 

 

【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();
}

 

  1. invokeBeanFactoryPostProcessors函数中完成第三步的扫描生成beanDefinitionMap.demo中的 xy对象

     

    再看下 beanDefinition对象中包含的内容,其中包含一些我们常见的属性 scope, autowireMode, abstructFlag

     

  2. finishBeanFactoryInitialization完成bean的实例化等过程,重点调试这块代码:

    3.1 在 finishBeanFactoryInitializationAbstractApplicationContext】完成第8步对象的实例化,在finishBeanFactoryInitialization 中的preInstantiateSingletonsDefaultListableBeanFactory】方法中校验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】->doGetBeanAbstractBeanFactory

        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】 -> doGetBeanAbstractBeanFactory】->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;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值