从源码角度解读Spring循环依赖 --- 三级缓存各自作用

前言

对于循环依赖,我相信读者无论只是听过也好,还是有过了解也好,至少都有所接触。但是我发现目前许多博客对于循环依赖的讲解并不清楚,都提到了Spring的循环依赖解决方案是三级缓存,但是三级缓存每一级的作用是什么,为什么要这样设计三级缓存,很多博客都没有提到。为了让大家能够更加清晰的理解Spring的循环依赖,下面我便带领大家从Spring源码的角度出发,讲解Spring循环依赖的整个流程以及其解决方案 —— 三级缓存的作用。

提示

此文章建议读者先阅读一下Spring创建bean流程的代码,这样再读这篇文章体会会明显一些
若是读者就想知道结论,建议直接从目录四开始看
若是读者已经知道Spring创建bean的流程,那也建议直接从目录四开始看

一、首先说明什么是循环依赖

比如,现在有两个类,OrderService和UserService(下面文章中我们简称其为os和us,并且就以这两个类作为演示),所谓的Spring循环依赖就是在os中依赖了us,us中依赖了os。按照正常的流程来说:

  1. Spring根据字典序优先创建os的bean,但是容器中没有os的bean,便创建os的bean
  2. 在创建os的过程中发现需要属性注入us,然而容器中也没有us的bean,这时便开始创建us
  3. 创建us的过程中其发现需要属性注入os,容器中也没有存放os的bean,就又开始创建os…

如此便进入了死循环中。但是Spring中是否真是如此呢?我们来代码演示一下:
这里是 os类,其中依赖了us

@Component
public class OrderService {
   
   
	@Autowired
	private UserService userService;

	public OrderService(){
   
   
		System.out.println("start orderService");
	}
}

这里是 us类,其中依赖了os

@Component
public class UserService {
   
   
	@Autowired
	private OrderService orderService;

	public UserService(){
   
   
		System.out.println("start userService");
	}

}

这里是测试类

public class Test {
   
   
	public static void main(String[] args) throws Exception {
   
   
		AnnotationConfigApplicationContext ac =
				new AnnotationConfigApplicationContext();
		ac.register(Appconfig.class);
		ac.refresh();
		//关闭循环依赖
//		ac.setAllowCircularReferences(false);

		System.out.println(ac.getBean(OrderService.class));
		System.out.println(ac.getBean(UserService.class));

	}
}

运行结果如下:

我们可以看见os和us都是正常打印,并没有报错,说明Spring是做了 某些处理 使其允许循环依赖。其实Spring是提供了关闭循环依赖的api的,比如上面测试类代码中注释掉的那句话,我们打开那个注释,再运行一次。
在这里插入图片描述
可以看见直接运行报错,报错信息大家可以自己下去测试看看。
这里再说明有两种情况下Spring是不支持循环依赖的,原因大家可以自行了解一下。




  1. 当bean的作用域是原型的时候
  2. 当以构造器的形式注入的时候

下面文章,我就来详细讲解 某些处理 到底是什么处理。

二、循环依赖三级缓存以及整个流程介绍

首先给三级缓存在Spring中到底是哪三级,在 DefaultSingletonBeanRegistry 类中:

	/** Cache of singleton objects: bean name to bean instance. */
	// 一级缓存,可称为单例池,存放创建好的单例bean的map beanName - bean
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	// 三级缓存,存放的结构是 beanName - ObjectFactory
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	// 二级缓存,存放的结构是 beanName - bean
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

因为Spring的循环依赖解决只是bean的生命周期中的一个很小的部分,其归属的部分是属性填充时期,意思就是循环依赖是在属性填充时期发生并解决的。bean生命周期大概如下:

  1. 推断构造方法
  2. 实例化对象
  3. 属性填充
  4. 生命周期回调初始化方法

为了让大家能够更加清晰的理解Spring的循环依赖,这里先用文字描述一下,Spring创建bean解决循环依赖的的大概流程(下面的源码叙述就围绕这个流程展开

  1. Spring优先创建os,在调用getSingleton 获取os的bean的时候,发现单例池中没有,所以会createBean,并将os放入正在创建的容器中;
  2. 进行os对象的实例化,然后将os放入三级缓存中,接着对os进行属性填充,执行某个后置处理器
    方法完成属性填充;
  3. 属性填充时发现os中的属性是us,就会取getBean,但是拿不到us(还未创建),所以会createBean创建us的bean,并将us放入正在创建的容器中;
  4. 进行us对象的实例化,然后将us放入三级缓存中,接着对us进行属性填充;
  5. 属性填充时,发现us中的属性是os,但是得到os的bean为空,并且os现在是属于在正在创建的,所以再次调用getSingleton 会从三级缓存中得到os;
  6. 到此us属性填充完毕,us这个bean存入单例池(一级缓存),方法栈返回,将us注入到os中,完成循环依赖。

到这里我相信大家可能会有如下几个疑问:

  1. 为什么要设置三级缓存?各自作用是什么?
  2. 第三级缓存的value值类型为什么和前两级不一样?
  3. 在上述流程中的步骤2说的某个后置处理器是哪个后置处理器?
  4. 在上述流程中的步骤5中,调用getSingleton 如何从三级缓存中获取bean?

三、源码叙述Spring循环依赖

将上面流程转化为具体的源码调用,如下:
1、流程的第一步。

Spring优先创建os,在调用getSingleton 获取os的bean的时候,发现单例池中没有,所以会createBean,并将os放入正在创建的容器中。

(1)代码调用如下:

ac.refresh();

//这个方法的功能之一就是完成类的实例化和属性注入
finishBeanFactoryInitialization(beanFactory);

//实例化所有的非lazy的单例bean
beanFactory.preInstantiateSingletons();

(2)进入这个 preInstantiateSingletons() 方法中(一些不怎么必要的逻辑,我就直接省略了),在这个方法里面会得到所有的beanDefinition(这个东西就是用于描述一个bean的,大家可以自己去了解一下,这里不做展开)的名称,判断这个bean是否是FactoryBean或者是一个普通的bean,这里我们的os是一个普通的bean(一般来说都是一个普通的bean),进入else,调用getBean(String) 方法。

@Override
public void preInstantiateSingletons() throws BeansException {
   
   
   //这里得到所有的 bd名字
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   // 这里就遍历所有的bd,然后进行所有非惰性单例的bean的初始化
   for (String beanName : beanNames) {
   
   
      // 根据bd名字看是否需要合并获取其 bd
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      //如果这个bd不是抽象的,是单例的,不是lazy的,那就表示其现在可以进行初始化
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
   
   
         //如果这个bean是一个 FactoryBean
         if (isFactoryBean(beanName)) {
   
   
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
   
   
               ...
            }
         }
         // 否则是一个普通的bean
         else {
   
   
            // 根据beanName获取一个bean。
            getBean(beanName);
         }
      }
   }
    ...
}

(3)进入 getBean(String) 方法,里面调用的的是doGetBean 方法

@Override
public Object getBean(String name) throws BeansException {
   
   
   return doGetBean(name, null, null, false);
}

(4)进入 doGetBean 方法,在这个方法中会调用 getSingleton(String) 方法!!!!注意这个getSingleton(String) 方法,很重要,这个方法就是解决循环依赖的根本方法。第一次调用 getSingleton(String) 得到os的bean为null,便会再次调用重载的 getSingleton(String, ObjectFactory) 方法。

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
   
   

   // 可以理解为验证bean的名字是否合法,若是合法则将bd map中的key作为beanName
   // 在获取factoryBean的时候 若是加上 & 则是获取FactoryBean对象本身的bean,不加 & 则是获取返回的对象的bean
   String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   // getSingleton !!!!!  重点方法!!!!
   // 这里就从 singletonObjects(单例池) 容器中直接拿,下面代码中还会调用其重载的 getSingleton
   // 第一次获取的肯定是null
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
   
   
       ...
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
   
   
    ...
      if (!typeCheckOnly) {
   
   
         markBeanAsCreated(beanName);
      }

      try {
   
   
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
   
   
            ...
         }

         // Create bean instance.
         if (mbd.isSingleton()) {
   
   
            // 这里再次调用 getSingleton (重载的)
            sharedInstance = getSingleton(beanName, () -> {
   
   
               // 这个lambda表达式的逻辑就是为了创建一个单例bean
               try {
   
   
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
   
   
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
   
   
           ...
         }
      }
      catch (BeansException ex) {
   
   
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && !requiredType.isInstance(bean)) {
   
   
      ...
   }
   return (T) bean;
}

(4.1)这里给出 getSingleton(String) 方法逻辑,可以看到参数2Spring直接给的true,在 getSingleton(String , boolean) 方法中,第一次调用会返回null。

@Override
@Nullable
public Object getSingleton(String beanName) {
   
   
	// 参数2直接给的true
   return getSingleton(beanName, true);
}


@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   
   
   // Quick check for existing instance without full singleton lock
   // 首先从一级缓存 singletonObjects 单例池直接获取,singletonObjects就是bean的单例池
   Object singletonObject = this.singletonObjects.get(beanName);

   // 如果从一级缓存 单例池中获取的bean为空,并且该bean正在被创建
   // 第一次运行进来第二个条件肯定不满足,不进入if,直接返回 singletonObject
   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) {
   
   
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

(4.2)这里给出 getSingleton(String, ObjectFactory) 方法逻辑,里面的beforeSingletonCreation(String) 方法就将当前正在创建bean存入了表示正在创建的集合 singletonsCurrentlyInCreation 中,即将os存入其中。singletonObject = singletonFactory.getObject(); 这个这句话就得到创建好的bean,但是singletonFactory是哪里来的呢?他其实是由外部的lambda表达式实现的。在外部的lambda表达式中就调用了 createBean(…) 这个方法去创建了一个单例的bean。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   
   
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
   
   
      // 这里仍然从容器当中拿一次
      Object singletonObject = this.singletonObjects.get(beanName);
      // 拿到了就返回,没有拿到就进入这个if
      if (singletonObject == null) {
   
   
         if (this.singletonsCurrentlyInDestruction) {
   
   
            ...
         }
         if (logger.isDebugEnabled()) {
   
   
            ...
         }
         // 将当前beanName存入正在创建bean的set集合中
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
   
   
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
   
   
            // 这个getObject() 的逻辑就是该方法外部的lambda 表达式
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
   
   
            ...
         }
         finally {
   
   
            ...
            afterSingletonCreation(beanName);
         }
         // 将创建好的单例bean存入单例池中
         if (newSingleton) {
   
   
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

(4.2.1)这里给出beforeSingletonCreation(String)的逻辑
其作用就是将该beanName放入了这个表示正在创建的集合 singletonsCurrentlyInCreation中

protected void beforeSingletonCreation(String beanName) {
   
   
   //这里完成的功能就是,判断当前检查中是否包含该bean,并且判断该bean是否在正在创建,注意这里是add
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
   
   
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

以上代码就是流程的第一步:
Spring优先创建os,在调用getSingleton 获取os的bean的时候,发现单例池中没有,所以会createBean,并将os放入正在创建的容器中;

2、流程的第二步。

进行os对象的实例化,然后将os放入三级缓存中,接着对os进行属性填充,执行某个后置处理器方法完成属性填充;

(4.3)这里给出getSingleton(String, ObjectFactory) 参数2的lambda表达式逻辑
在(4.2)中有这样一句代码getObject() ,由于lambda表达式的异步性,所以当调用getObject() 方法时才会执行lambda表达式,在lambda表达式中调用了一个方法 createBean(beanName, mbd, args) 而createBean 的返回值就是 getObject()所得到的对象。在 createBean 中又继续调用了doCreateBean 方法得到了一个完整的bean。

// 这个getObject() 的逻辑就是该方法外部的lambda 表达式
singletonObject = singletonFactory.getObject();

// lambda表达式如下
() -> {
   
   
   // 这个lambda表达式的逻辑就是为了创建一个单例bean
   try {
   
   
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
   
   
      destroySingleton(beanName);
      throw ex;
   }
}

//其中 createBean(beanName, mbd, args) 方法逻辑如下
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   
   

   if (logger.isTraceEnabled()) {
   
   
      ...
   }
   RootBeanDefinition mbdToUse = mbd;

   // Make sure bean class is actually resolved at this point, and
   // clone the bean definition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean definition.
   // 从beanDefinition对象中获取出来bean的类型,因为实例化对象就需要类
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
   
   
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
   
   
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
   
   
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
   
   
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 第一次调用后置处理器 --- 与aop有关
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      // 90%的情况这里的bean就是为空,因为这里是做aop的属性设置
      if (bean != null) {
   
   
         return bean;
      }
   }
   catch (Throwable ex) {
   
   
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
   
   
      // 这里就会来进行bean的创建 将beanName,bd,和一些参数传入开始进行bean的创建
      // beanInstance就是实例化好的一个完整的bean
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
   
   
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
   
   
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
   
   
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

(5)这里给出 doCreateBean(beanName, mbdToUse, args) 方法的逻辑
在这个方法中,在执行 createBeanInstance(beanName, mbd, args) 方法的时候会进行实例化os对象,里面完成了推断构造方法 和 实例化对象,但是此时并未注入属性。后面初始化了一个 boolean类型的值 earlySingletonExposure,因为此时os是单例的,并且Spring是允许循环依赖的,并且os也在正在创建的那个集合中,所以此时这个boolean值就为true。如此便会进入下面的那个if之中,调用addSingletonFactory() 方法(查看5.1)将os以ObjectFactory的形式存入了三级缓存中。后面便调用了 populateBean(beanName, mbd, instanceWrapper) 方法完成了属性注入。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   
   

   // Instantiate the bean.
   // 这里开始实例化bean
   BeanWrapper instanceWrapper = null;
   // 如果是单例的
   if (mbd.isSingleton()) {
   
   
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
   
   
      // 实例化对象,里面第二次调用后置处理器 --- 这里面完成了推断构造方法 和 实例化对象(还未注入属性!!!!)
      // 得到的 instanceWrapper 就是实例化好的对象的包装类
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 这里就通过bean的包装类得到了该bean的实例和类型
   Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
   
   
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
   
   
      if (!mbd.postProcessed) {
   
   
         ...
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   // 判断是否允许进行循环依赖并且提前暴露这个单例bean,注意这里很重要,
   // 这个boolean值与 getSingleton(String, boolean) 方法是密切相关的
   // 条件1:该bean是否单例
   // 条件2:该类的 allowCircularReferences 属性,这个属性默认为true,那就是直接体现Spring是默认支持循环依赖的
   // 条件3:该bean是否是正在创建的(beanName是否在正在创建的容器之中)
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
   
   
      ...
      // 第四次调用后置处理器,判断是否需要进行 AOP
      // 参数2是一个ObjectFactory --- 对象工厂,使用的是lambda表达式
      // 这里提前暴露一个对象工厂,而不是一个bean对象!!!
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
   
   
      // 这里面进行属性填充,即常说的自动注入
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
   
   
      ...
   }

   if (earlySingletonExposure) {
   
   
      ...
   }

   // Register bean as disposable.
   try {
   
   
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
   
   
      ...
   }

   return exposedObject;
}

(5.1)这里给出 addSingletonFactory(String, ObjectFactory)的逻辑
此时就将os以ObjectFactory的形式存入了三级缓存中。

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   
   
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
   
   
      // 若是一级缓存中没有这个bean,表示这个bean还没有创建完毕
      if (!this.singletonObjects.containsKey(beanName)) {
   
   

         // 三级缓存中添加该 对象工厂
         this.singletonFactories.put(beanName, singletonFactory);

         // 二级缓存中移除该bean,这里为什么要移除
         // 我认为这里移除的原因有两点:
         // 1、就是为了让程序在调用 getSingleton(String, boolean) 方法的时候,进入第二个if,就是同步代码块中。
         // 2、从二级缓存中移除一个旧的bean,便于三级缓存重新生产一个新(重新进行aop等操作)对象
         this.earlySingletonObjects.remove(beanName);

         // 将该beanName存放到表示保存已经注册好的bean的集合中
         this.registeredSingletons.add(beanName);
      }
   }
}

5.2、这里给出lambda表达式() -> getEarlyBeanReference(beanName, mbd, bean)中方法的逻辑
这个lambda的调用时机是在 getSingleton(String) 这个方法里面
其与aop相关,所以Spring其实是很早就进行了aop的,而不只是生命周期的那个时间段(请注意这句话)。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   
   
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
   
   
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

6、这里给出populateBean(beanName, mbd, instanceWrapper) 方法的逻辑
在这个方法中首先会执行InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation()方法。实际上我们可以自己实现InstantiationAwareBeanPostProcessor接口,然后重写postProcessAfterInstantiation()方法,让其返回false,便可以对指定的bean设置其不允许循环依赖。
后面代码中最重要的便是 InstantiationAwareBeanPostProcessor这个后置处理器的 postProcessProperties() 方法调用,这个方法就完成了属性注入。其实现类 AutowiredAnnotationBeanPostProcessor 便完成了了 @Autowired 注解的实现,另外一个实现类 CommonAnnotationBeanPostProcessor 完成了 @Resources 注解的实现。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   
   
   if (bw == null) {
   
   
      if (mbd.hasPropertyValues()) {
   
   
         ...
      }
      else {
   
   
         // Skip property population phase for null instance.
         return;
      }
   }

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   // 判断要不要进行属性注入。
   // 我们自己可以实现 InstantiationAwareBeanPostProcessor 这个接口,
   // 重写其中 postProcessAfterInstantiation() 方法使其返回false,则可以不再进行属性注入
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
   
   
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
   
   
               return;
            }
         }
      }
   }

   // pvs是表示你有没有给我的属性传入值
   // 比如当使用xml的形式时,有ref指定该属性需要传入的值是什么,但是 @Autowired 没法指定值所以会得到null
   // 正因为是null 所以其开始进行属性自动注入
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   // 得到该bean的自动注入模式,@Autowired 的自动注入模式为 0
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();

   // 判断该注入模式是byName还是byType,所以@Autowired 不会进入这个判断
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
   
   
      ...
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
   
   
      if (pvs == null) {
   
   
         pvs = mbd.getPropertyValues();
      }
      // 在 getBeanPostProcessors() 中会得到6个 bean后置处理器
      // 其中一个叫 CommonAnnotationBeanPostProcessor 这个bean后置处理器就是处理 @Resource 注解的
      // 还有一个叫 AutowiredAnnotationBeanPostProcessor 这个bean后置处理器就是处理 @Autowired 注解的
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
   
   
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 这里就是执行 对应后置处理器的重写方法
            // @Autowired 注解便会执行 AutowiredAnnotationBeanPostProcessor 这个后置处理器的重写方法
            /** AutowiredAnnotationBeanPostProcessor后置处理器的这个方法就是完成属性填充 */
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
   
   
              ...
            }
            pvs = pvsToUse;
         }
      }
   }
   if (needsDepCheck) {
   
   
      ...
   }

   if (pvs != null) {
   
   
      ...
   }
}

以上代码就是流程的第二步:
进行os对象的实例化,然后将os放入三级缓存中,接着对os进行属性填充,执行某个后置处理器
方法完成属性填充;

上述流程中的第三,四,五步其实就是在循环做上述任务,第六步时属性已经填充完毕,循环依赖早已解决

如果你仔细观看了上述文章并且有结合Spring源码进行阅读,你就会发现,getSingleton(String) 与 addSingletonFactory(String, ObjectFactory) 这两个方法尤为重要,他们就是Spring解决循环依赖的根本逻辑。

四、重点说明getSingleton(String) 和 addSingletonFactory(String, ObjectFactory)

在说明这两个方法之前,再总结一下循环依赖的流程:

  1. get os的bean,调用getSingleton(String) 但是为null;
  2. 将os放入表示正在创建的集合中;
  3. 实例化os的对象;
  4. 调用addSingletonFactory(String, ObjectFactory) 将os所对应的 ObjectFactory放入三级缓存;
  5. os对象进行属性填充;
  6. os属性填充时发现属性是us,调用 getSingleton(String) 获取us的bean,但是为null;
  7. 将us放入表示正在创建的集合中;
  8. 实例化us的对象;
  9. 调用addSingletonFactory(String, ObjectFactory) 将us所对应的 ObjectFactory放入三级缓存;
  10. us进行属性填充;
  11. us进行属性填充时,发现属性是os,就调用 getSingleton(String) 获取us的bean,这是能够获取到,us属性填充完毕;
  12. us初始化完成,方法栈返回,os属性填充完毕,os初始化完成。

为了方便说明,下面再次给出 addSingletonFactory(String, ObjectFactory) 方法源码

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   
   
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
   
   
      // 若是一级缓存中没有这个bean,表示这个bean还没有创建完毕
      if (!this.singletonObjects.containsKey(beanName)) {
   
   

         // 三级缓存中添加该 对象工厂
         // 这里提前暴露一个对象工厂,而不是一个bean对象
         this.singletonFactories.put(beanName, singletonFactory);

         // 二级缓存中移除该bean,这里为什么要移除
         // 我认为这里移除的原因有两点:
         // 1、就是为了让程序在调用 getSingleton(String, boolean) 方法的时候,进入第二个if,就是同步代码块中。
         // 2、从二级缓存中移除一个旧的bean,便于三级缓存重新生产一个新(重新进行aop等操作)对象
         this.earlySingletonObjects.remove(beanName);

         // 将该beanName存放到表示保存已经注册好的bean的集合中
         this.registeredSingletons.add(beanName);
      }
   }
}

其中参数2的ObjectFactory,是由一个lambda表达式传入的,下面给出这个lambda表达式的源码
这个lambda表达式中的那个后置处理器完成的一个功能就是进行了aop!看到这,我相信有些读者应该已经知道了第三级缓存value值为什么是一个 ObjectFactory了,如果还不知道,也没事,下面会解释。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   
   
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
   
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
   
   
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

再说明 getSingleton(String) 方法,这里再次给出其方法源码
这个方法其实也没有什么难懂的逻辑,看看注释也就知道他在干嘛了。

@Override
@Nullable
public Object getSingleton(String beanName) {
   
   
   return getSingleton(beanName, true);
}


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   
   
   // Quick check for existing instance without full singleton lock
   // 首先从一级缓存 singletonObjects 单例池直接获取,singletonObjects就是bean的单例池
   Object singletonObject = this.singletonObjects.get(beanName);

   // 如果从一级缓存 单例池中获取的bean为空,并且该bean正在被创建
   // 第一次运行进来第二个条件肯定不满足,不进入if,直接返回 singletonObject

   // 但是如果有循环依赖的情况,这个条件就会满足!!!!
   // 如下代码就是Spring解决循环依赖的实现过程
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
   
   
      // 从二级缓存中获取
      singletonObject = this.earlySingletonObjects.get(beanName);
      // 如果一级缓存中为空,并且表示允许提前引用(这个条件从getBean的流程过来,Spring直接给的true)
      // allowEarlyReference在这里直接默认为true,表示允许提前引用???
      // 我觉得这个提前引用的意思就是(注意这个if的位置):因为循环引用的原因,导致这个时候的bean还是一个不完整的,
      // 但是一个不完整的bean怎么能够给别人使用呢,所以这里需要进行一个判断,是否允许一个不完整的bean提供给别人
      // 当一个不完整的bean给被别人使用的时候,最后还是得让其变得完整,所以这里使用了ObjectFactory。
      // 由于循环依赖的特殊性,所以这里为true。这里也可以作为Spring允许循环依赖的源码级别证据之一。
      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) {
   
   
                  // 那就从三级缓存中获取
                  // 三级缓存存放对象工厂的时机是在属性注入之前,并且earlySingletonExposure为true
                  // 所以当有循环依赖的时候,Spring就会从三级缓存中拿到这个不完整的bean,进行属性注入
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  // 若是三级缓存中拿到了
                  if (singletonFactory != null) {
   
   
                     // 得到 bean实例,注意这个 singletonFactory.getObject()得到bean 是使用lambda表达式完成的。
                     // 而lambda是异步进行的,即调用方法时才会执行。
                     // 而在这个表达式方法中完成了一个后置处理器的调用才返回了这个bean
                     // 这个后置处理器所完成的任务就是对循环依赖时的aop的解决。
                     singletonObject = singletonFactory.getObject();
                     // 将解决好aop问题的bean实例放入二级缓存中!!!!!
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     // 将该对象工厂从三级缓存中移除,因为解决好aop问题的bean实例已经存放入二级缓存中
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

这里说明第三级缓存为什么是一个ObjectFactory?
我们通过一个问题来说明

一个普通bean进行aop的过程:
new A -> 执行属性注入 -> 生命周期回调 -> 判断aop代理 -> put 一级缓存

当循环依赖时有aop的执行过程:比如这里有A B两类的循环依赖,A进行了aop:
A实例化对象(A还是一个简单对象没有aop) -> 属性注入B -> get B -> new B
 -> 注入A(此时A还是一个简单对象,没有进行aop),A注入到B -> B put到容器 -> B注入到A
 -> 生命周期回调 -> aop -> A put到容器
------->   可以看到此时的问题就是A是进行了aop的,但是B中的A却是一个没有进行aop的简单对象

所以这里三级缓存使用ObjectFactory的原因就在这里:
ObjectFactory 可以对对象进行任意修改,而这里的使用就是完成了循环依赖情况下的aop的代理的实现。singletonFactory.getObject() 所得到的对象就是上述lambda 表达式中方法getEarlyBeanReference(beanName, mbd, bean) 的返回对象,而这个方法中会调用后置处理器完成aop,这样便解决了上面所说的问题。

到这里,我相信很多读者应该已经知道了三级缓存各自的作用了吧,可能你会问二级缓存不是没有说吗?但是这二级缓存的作用和存在的意义读者可以思考一下,不过也没关系,下面总结也会提到。

五、总结

这里的总结也就是回答上面提到的四个问题:

问题1:为什么要设置三级缓存,各自的作用是什么?
Spring设计这三级缓存的原因,很大程度上就是为了解决循环依赖所带来的一系列问题
其各自的作用:

一级缓存:单例池,就是为了存放实例化好的bean

二级缓存:我认为设置二级缓存的目的是为了填补空白期,当三级缓存创建好了解决aop问题的bean到这个bean存入一级缓存(单例池)的这个空白期使用。当在多线程情况下,若是没有这个二级缓存,此时三级缓存已经移除,而一级缓存又没有存入,就会出现问题。可能有人会问为什么不直接使用三级缓存,而要设计一个二级缓存,我认为是因为一个效率问题,工厂创建bean还是需要时间,不如先直接把这个解决好aop问题的bean拿出来。

三级缓存:使用ObjectFactory完成了循环依赖情况下的aop的代理问题解决

问题2:第三级缓存的value值为什么和前两级不一样?

答案已经在问题1的回答里面了

问题3:在上述流程中的步骤2说的某个后置处理器是哪个后置处理器?

一个叫 CommonAnnotationBeanPostProcessor 这个bean后置处理器就是处理 @Resource 注解的
还有一个叫 AutowiredAnnotationBeanPostProcessor 这个bean后置处理器就是处理 @Autowired 注解的

问题4:在上述流程中的步骤5中,调用getSingleton 如何从三级缓存中获取bean?

这个问题的答案就在 getSingleton(String) 方法中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章