Spring源码之循环依赖

        什么是循环依赖?

        很简单,就是A对象依赖了B对象,B对象依赖了A对象。比如:

// A依赖了B
class A{
  public B b;
}

// B依赖了A
class B{
  public A a;
}

        如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的情况。比如:

A a = new A();
B b = new B();
a.b = b;
b.a = a;

        因为在Spring中,一个对象并不是简单的new出来,而是会经过Bean的生命周期各种情况都要考虑,就是因为Bean的生命周期所以才会出现循环依赖问题。当然,在Spring中,出现循环依赖的场景很多,有的场景Spring自动帮我们解决了,而有的场景则需要程序员来解决,下面详细说:

1. 单例循环依赖(支持)

        通常来说,如果问Spring内部如何解决循环依赖,一定是默认的单例Bean中,属性互相引用的场景。

        在bean的实例化过程中,我们doGetBean()方法

        所属类:org.springframework.beans.factory.support.AbstractBeanFactory

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

		// Instantiate the bean.
		// BeanWrapper是在实例化之后的对象上又做了包装
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 有可能在Bean创建之前,就是其他Bean把当前Bean创建出来了(比如依赖注入过程中)
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 创建实例,重点看****
			// 1.实例化有@Bean注解对应的实例
			// 2.实例化有@Autowired注解的有参构造函数
			// 3.实例化没有@Autowired注解的有参构造函数
			// 4.实例化无参构造函数
			// 实例化之后堆内存中有了该实例,但是属性却是空的(一个不完整的对象)
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 从BeanWrapper中拿真正的实例对象
		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) {
				try {
					/**
					 * TODO CommonAnnotationBeanPostProcessor支持@PostConstruct、@PreDestroy、@Resource注解
					 *     AutowiredAnnotationBeanPostProcessor支持@Autowired、@Value注解
					 *     收集注解:对类中注解的装配过程
					 *     这个方法是BeanPostProcessor接口的典型运用, 重要程度5,必须看
					 *     收集类中有注解的属性和方法,包装成对象,并将对象加入到容器,并把容器包装成InjectionMetadata对象,并放到缓存中
					 *     缓存是beanName和InjectionMetadata的对应关系,然后通过这个对象可以知道哪个属性或方法上有注解,为下面的属性填充做准备
					 */
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 如果是单例、并支持循环依赖、并且容器中有正在创建的Bean就返回true(解决循环依赖)
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 循环依赖,添加三级缓存,即执行getEarlyBeanReference():判断当前Bean是否需要AOP
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			/**
			 * (属性填充)IOC、DI,依赖注入的核心方法,重要程度:5,
			 *  主要是完成@Autowired、@Resource、xml配置方式的依赖注入,在此之前,堆内存已经有实例,只是属性为空
			 */
			populateBean(beanName, mbd, instanceWrapper);
			/**
			 * (初始化)Bean实例化+IOC依赖注入完成之后执行,重要程度:5
			 * 	@PostConstruct注解方法-->InitializingBean接口的afterPropertiesSet()方法-->init-method属性,AOP代理对象的生成入口
			 */
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		// 如果支持循环依赖
		if (earlySingletonExposure) {
			// 从二级缓存中拿是可以拿到的
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				// 比较代理对象和原始对象是否一样,大部分情况一样,因为都是原始对象
				if (exposedObject == bean) {
					// 如果一样的话把二级缓存拿到的对象赋值给原始对象
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					// beanName被哪些bean依赖了,现在发现beanName所对应的Bean对象发声了改变,则会报错
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			// 注册Bean销毁时的类DisposableBeanAdapter
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

        进入getSingleton()方法:

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

        继续进入:

         所属类:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 根据beanName从缓存中拿实例,先从一级缓存拿
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果bean还正在创建,还没创建完成,其实是堆内存有了,属性还没有DI依赖注入
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 为什么要加锁?保证下面二级缓存和三级缓存方法执行的原子性
			synchronized (this.singletonObjects) {
				// 从二级缓存中拿
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 如果还拿不到,并且允许bean提前暴露
				if (singletonObject == null && allowEarlyReference) {
					// 从三级缓存中拿(单例工厂)
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 从三级缓存拿对象,会调到getEarlyBeanReference()方法,返回结果是原始对象或代理对象
						singletonObject = singletonFactory.getObject();
						// 得到结果后放到二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 删除三级缓存(为了减少bug)
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

        在DefaultSingletonBeanRegistry类中,你会发现类上方挂着这三个Map,也就是我们通常说的三级缓存。

  • singletonObjects它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例Bean的地方(一级缓存)。
  • earlySingletonObjects映射Bean的早期引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance(二级缓存),当存在三个以上对象的循环依赖时,同一个对象的getBean() 的时候,就需要用到。
  • singletonFactories映射创建Bean的原始工厂(三级缓存)。

        三级缓存只会调一遍,后两个Map其实是“垫脚石”级别的,只是创建Bean的时候,用来借助了一下,创建完成就清掉了。

        为什么后两个Map为垫脚石,假设最终放在singletonObjects的Bean是你想要的一杯“凉白开”。那么Spring准备了两个杯子,即singletonFactories和earlySingletonObjects来回“倒腾”几番,把热水晾成“凉白开”放到singletonObjects中。

        如果缓存中能拿到实例则返回,拿不到则创建实例,就会进入doGetBean()中下面的else分支,进入getSingleton() 方法:

所属类:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

/**
 * TODO 获取单例bean,第二个参数ObjectFactory是函数式接口,里面有个getObject()方法
 */
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 (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }

         // 把beanName添加到singletonsCurrentlyInCreation Set容器中,在这个集合里面的bean都是正在实例化的bean
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            // getObject()会调到前面匿名类的createBean()方法;如果这里有返回值,就表示这个bean已经创建成功
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            // 把beanName从singletonsCurrentlyInCreation容器中删除,表示实例化已经完成
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
             // 将创建成功的Bean放到一级缓存中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

        把beanName存入到singletonsCurrentlyInCreation (Set)容器中,标识作用,表示当前的类正在实例化,进入beforeSingletonCreation() 方法:

protected void beforeSingletonCreation(String beanName) {
   // 把beanName添加到singletonsCurrentlyInCreation (Set)容器中, 在这个集合里面的bean都是正在实例化的bean
   // 循环依赖时用到这容器,校验bean时候正在创建,已经正在创建了就会抛出下面的异常
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

        实例化已经完成 把beanName从singletonsCurrentlyInCreation容器中删除,进入afterSingletonCreation():

protected void afterSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
   }
}

        singletonObject = singletonFactory.getObject();如果这里有返回值,就表示这个bean已经创建成功,然后放到一级缓存,并把二、三级缓存删掉,进入addSingleton():

所属类:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      // 一级缓存
      this.singletonObjects.put(beanName, singletonObject);
      // 二级缓存
      this.singletonFactories.remove(beanName);
      // 三级缓存
      this.earlySingletonObjects.remove(beanName);
      // 提供给外部的API时,统计功能
      this.registeredSingletons.add(beanName);
   }
}

        我们着重看createBean() ——>doCreateBean()) ——>createBeanInstance() 无参构造函数的实例化,此时,堆内存中的A实例还没依赖注入,仅在内存中开辟了一块空间,它引用的B对象还为null。

        在createBeanInstance() 和populateBean() 之前还有一个addSingletonFactory()方法,用来设置三级缓存,前提是单例、允许循环依赖、bean还正在创建中,因为创建成功后,会在afterSingletonCreation() 中从容器中删除。

// TODO 添加三级缓存,即执行getEarlyBeanReference(),这里着重理解,助于理解循环依赖,
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

        它定义了一个匿名内部类,通过getEarlyBeanReference方法获取代理对象,其实底层是通过AbstractAutoProxyCreator类的getEarlyBeanReference()方法生成代理对象。

        所属类:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		// 进来拿循环依赖中第二次创建的A对象,拿到A对象后表示B对象需要依赖注入的A对象拿到了,那么,也代表B对象的实例化完成了
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					// BeanPostProcessor的应用,在某个关键的地方埋点,是个装饰者设计模式:
					// 从BeanPostProcessor中拿到所有实例去遍历,反复的对同一个对象exposedObject进行装饰,
					// 这里的装饰不一定是修改,也可以是调用
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

        顺便提一下,如果需要修改exposedObject,可以实现SmartInstantiationAwareBeanPostProcessor接口,重写getEarlyBeanReference() 方法,Spring给我们提供了这样的扩展,灵活性很高。

        会进一步调用getEarlyBeanReference()方法:

        所属类:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

	// 出现循环依赖会调用到这里
	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 在这个Map中记录一下当前实例化的Bean进行了AOP
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

        在整个Spring中,默认就只有AbstractAutoProxyCreator真正意义上实现了
getEarlyBeanReference方法,而该类就是用来进行AOP的。
AnnotationAwareAspectJAutoProxyCreator的父类就是AbstractAutoProxyCreator。
        那么getEarlyBeanReference方法到底在干什么? 首先得到一个cachekey,cachekey就是
beanName。 然后把beanName和bean(这是原始对象)存入earlyProxyReferences中 调用
wrapIfNecessary进行AOP,得到一个代理对象。

    // 如果当前实例化Bean需要AOP,则生成代理,否则,返回原始对象
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// earlyProxyReferences是一个ConcurrentHashMap,里面存放的是需要进行AOP的Bean
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 生成当前实例化bean的代理对象**
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

        那么,什么时候会调用getEarlyBeanReference方法呢?

        回到循环依赖的场景中,在getSingleton()方法中,存入singletonFactories时并不会执行lambda表达式,也就是不会执行getEarlyBeanReference方法。

         从singletonFactories根据beanName得到一个ObjectFactory,然后执行ObjectFactory,也就是执行getEarlyBeanReference方法,此时会得到一个A原始对象经过AOP之后的代理对象,然后把该代理对象放入earlySingletonObjects中,注意此时并没有把代理对象放入singletonObjects中,那什么时候放入到singletonObjects中呢?
        我们这个时候得来理解一下earlySingletonObjects的作用,此时,我们只得到了A原始对象的代理对象,这个对象还不完整,因为A原始对象还没有进行属性填充,所以此时不能直接把A的代理对象放入singletonObjects中,所以只能把代理对象放入earlySingletonObjects,假设现在有其他对象依赖了A,那么则可以从earlySingletonObjects中得到A原始对象的代理对象了,并且是A的同一个代理对象。
        当B创建完了之后,A继续进行生命周期,而A在完成属性注入后,会按照它本身的逻辑去进行AOP,而此时我们知道A原始对象已经经历过了AOP,所以对于A本身而言,不会再去进行AOP了,那么怎么判断一个对象是否经历过了AOP呢?会利用上文提到的earlyProxyReferences,在
AbstractAutoProxyCreator的postProcessAfterInitialization方法中,会去判断当前beanName是
否在earlyProxyReferences,如果在则表示已经提前进行过AOP了,无需再次进行AOP。
        对于A而言,进行了AOP的判断后,以及BeanPostProcessor的执行之后,就需要把A对应的对象放入singletonObjects中了,但是我们知道,应该是要把A的代理对象放入singletonObjects中,所以此时需要从earlySingletonObjects中得到代理对象,然后入singletonObjects中。
        整个循环依赖解决完毕。

        我们用一个图来串一下出现循环依赖时,Spring的解决过程:

         两个类的实例化顺序如下:

 2. 构造函数循环依赖(不支持)

@Component
public class CircularRefConA {

    private CircularRefConB circularRefConB;

    // @Lazy
    // 会触发入参对象B的getBean
    public CircularRefConA(CircularRefConB circularRefConB) {
//        circularRefConB.getB();
        this.circularRefConB = circularRefConB;
//        circularRefConB.getB();
        System.out.println("============CircularRefConA()===========");
    }

    public void getA(){

    }
}

@Component
public class CircularRefConB {

    private CircularRefConA circularRefConA;
    // @Lazy
    // 会触发入参对象A的getBean
    public CircularRefConB(CircularRefConA circularRefConA) {
//        circularRefConA.getA();
        this.circularRefConA = circularRefConA;
//        circularRefConA.getA();
        System.out.println("============CircularRefConB()===========");
    }

    public void getB() {

    }
}

        这种情况会报错:

         在getSingleton() 中的beforeSingletonCreation() 方法:

        所属类:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

protected void beforeSingletonCreation(String beanName) {
   // 把beanName添加到singletonsCurrentlyInCreation (Set)容器中, 在这个集合里面的bean都是正在实例化的bean
   // 循环依赖时用到这容器,校验bean是否正在创建,已经正在创建了就会抛出下面的异常
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

         异常就是在这抛出的,构造方法的循环依赖,直接报错,因为连对象都创建不了,更别说后面的A对象依赖B对象了,如何解决:构造方法加@Lazy注解。

3. 原型循环依赖(不支持)

        原型的情况,两个都是原型的话每次都创建新的Bean,没完没了~Spring不支持。

        不管是单线程多次调用getBean(),还是多线程多次调用getBean(),每次拿到的实例都不一样(hashCode不同),会创建多个实例。

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CircularRefPrototypeB {
    @Autowired
    private CircularRefPrototypeA circularRefPrototypeA;
}

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CircularRefPrototypeB {
    @Autowired
    private CircularRefPrototypeA circularRefPrototypeA;
}

        通常会走到AbstractBeanFactory类中的doGetBean() 中的:

// 多例的情况
else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      beforePrototypeCreation(beanName);
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
      afterPrototypeCreation(beanName);
   }
   // 该方法是FactoryBean接口的调用入口
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
   String scopeName = mbd.getScope();
   if (!StringUtils.hasLength(scopeName)) {
      throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
   }
   Scope scope = this.scopes.get(scopeName);
   if (scope == null) {
      throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
   }
   try {
      Object scopedInstance = scope.get(beanName, () -> {
          // 把实例放到threadLocal中
         beforePrototypeCreation(beanName);
         try {
            return createBean(beanName, mbd, args);
         }
         finally {
            afterPrototypeCreation(beanName);
         }
      });
      bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
   }
   catch (IllegalStateException ex) {
      throw new ScopeNotActiveException(beanName, scopeName, ex);
   }

        在这里少了一个单例的getSingleton()方法,getSingleton()会把创建的实例放到一级缓存中。多例的情况只管创建实例,创建完不会放到三级缓存,因为三级缓存只针对单例的情况。

        在创建新的A时,发现要注入原型字段B,又创建新的B发现要注入原型字段A...这就套娃了, 是先StackOverflow还是OutOfMemory?Spring怕你不好猜,就先抛出了BeanCurrentlyInCreationException。

/**
 * TODO:处理原型模式下循环依赖的问题
 *  触发场景:原型模式下,如果存在A中有B属性,B中有A属性,那么当依赖注入的时候,
 *  就会产生当A还没创建完的时候,由于对B的创建再次返回创建A,造成循环依赖;
 *  如果singletonObjects缓存里面没有,则走下来,
 *  如果是Scope是Prototype的,校验是否有出现循环依赖,如果有则直接报错
 */
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}

        多例的调用每一次都是单独的,新创建一个实例,所以放在ThreadLocal中。

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
   // threadLocal中有值
   Object curVal = this.prototypesCurrentlyInCreation.get();
   return (curVal != null &&
         (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
protected void beforePrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal == null) {
      // 第一次进来放到threadLocal中
      this.prototypesCurrentlyInCreation.set(beanName);
   }
   else if (curVal instanceof String) {
      Set<String> beanNameSet = new HashSet<>(2);
      beanNameSet.add((String) curVal);
      beanNameSet.add(beanName);
      this.prototypesCurrentlyInCreation.set(beanNameSet);
   }
   else {
      Set<String> beanNameSet = (Set<String>) curVal;
      beanNameSet.add(beanName);
   }
}

4.@Async异步情况(程序员解决)

@Service
publicclass AService1 {

    @Autowired
    private BService2 bService2;

    @Async
    public void test1() {
    }
}
@Service
publicclass BService2 {

    @Autowired
    private AService1 aService1;

    public void test2() {
    }
}

报错信息:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'aService1': Bean with name 'aService1' has been injected into other beans [bService2] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.

      原因:当循环依赖有AOP,又在AService加上@Async异步注解后,会报错,因为@EnabelAsync注解在Spring中会注册一个AysncAnnotationBeanPostProcessor的类,在执行初始化方法initializeBean()时会在AnnotationAwareAspectJAutoProxyCreator的方法执行之后再执行自己的postProcessAfterInitializeBean()方法,它自己也会生成一个代理对象,导致初始化方法返回的exposedObject对象和初始Bean不相同,就会进入else方法中,异常就是从这里抛出的。因为属性赋值的对象和放入单例池的对象不是同一个,那肯定不行。

        解决思路:依赖的属性上加@Lazy注解,会直接生成一个代理对象赋值给加@Lazy注解的属性,这样就不会产生循环依赖了。等到调用代理对象的方法时,才会创建原始Bean,但在容器启动的时候,Bean已经生成了,通过beanName找Bean对象即可,然后直接调用方法。

        另外,把@Async注解加在BService却不会报错,因为Spring是按顺序进行Bean的实例化,先实例化AServcie,再实例化BService。

5.DependsOn循环依赖(不支持)

@DependsOn(value = "testService2")
@Service
publicclass TestService1 {

    @Autowired
    private TestService2 testService2;

    public void test1() {
    }
}
@DependsOn(value = "testService1")
@Service
publicclass TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test2() {
    }
}

         程序启动之后,执行结果:

Circular depends-on relationship between 'testService2' and 'testService1'

        这又是为什么?

        答案在org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()方法的这段代码中:

// 总结:到这里,要准备创建Bean了,对于singleton的Bean来说,容器中还没创建过此Bean;而对于prototype的Bean来说,是要创建一个新的Bean。
			try {
				// 父子BeanDefinition合并
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 检查BeanDefiniiton是不是Abstract的
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 获取依赖对象信息(依赖对象须先实例化)
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						// dep为依赖的对象名,判断beanName是不是被dep依赖了,如果是则出现了循环依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 如果dep被beanName依赖,存入dependentBeanMap(dep为key,beanName为value)
						registerDependentBean(dep, beanName);
						try {
							// 创建所依赖的Bean*****
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

        它会检查dependsOn的实例有没有循环依赖,如果有循环依赖则抛异常。 

        最后,总结一下三级缓存:

  1. singletonObjects:单例池单例缓存了经过完整生命周期的Bean。
  2. earlySingletonObjects:解决循环依赖最重要的是二级缓存,它存的是一个半成品。缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整生命周期的bean。
  3. singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
  4. 其实还有一个缓存,就是earlyProxyReferences,用来记录某个原始对象是否进行过AOP。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值