A => B => A
一级缓存 singletonObjects
二级缓存 earlySingletonObjects
三级缓存 singletonFactories
1、获取A,从三级缓存中获取,没有获取到
2、构造A,将A置入三级缓存
3、注入属性,构造B
4、获取B,从三级缓存中没有获取到
5、构造B,将B置入三级缓存
6、注入属性,构造A
7、获取A,从三级缓存中获取,一级没有、二级没有、三级存在。此时通过从三级的BeanFactory构造实例对象,放入二级缓存,移除三级缓存
8、创建B实例后续步骤
9、B构造完成,实例放入一级缓存,二级三级缓存移除
10、创建A实例后续步骤
11、A构造完成,实例放入一级缓存,二级三级缓存移除
springboot 2.5.6
// AbstractBeanFactory#doGetBean 256行
protected <T> T doGetBean(String name, &#64;Nullable Class<T> requiredType, &#64;Nullable Object[] args, boolean typeCheckOnly)throws BeansException {
String beanName &#61; transformedBeanName(name);
Object beanInstance;// 从三个缓存中依次获取&#xff0c;注意方法点进去allowEarlyReference是true
Object sharedInstance &#61; getSingleton(beanName);...
// AbstractAutowireCapableBeanFactory#doCreateBean 582行
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, &#64;Nullable Object[] args)throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper &#61; null;
if (mbd.isSingleton()) {instanceWrapper &#61; this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper &#61;&#61; null) {
// 这里会通过构造函数创建Bean实例instanceWrapper &#61; createBeanInstance(beanName, mbd, args);
}
//省略代码...
// AbstractAutowireCapableBeanFactory#doCreateBean 613行
//省略代码...
boolean earlySingletonExposure &#61; (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean &#39;" &#43; beanName &#43;"&#39; to allow for resolving potential circular references");}// 这里会把生成beanName的BeanFactory置入三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//省略代码...
InitDestroyAnnotationBeanPostProcessor
会解析缓存类中&#64;PostStruct
和&#64;PreDestroy
等相关信息
CommonAnnotationBeanPostProcessor
会解析缓存类中&#64;Recource
、&#64;WebServiceRef
、&#64;PostStruct
和&#64;PreDestroy
等相关信息
AutowiredAnnotationBeanPostProcessor
会解析缓存类中&#64;Autowired
、&#64;Value
、&#64;Inject
等相关信息
// AbstractAutowireCapableBeanFactory#doCreateBean 594行
//省略代码...
synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {// 解析缓存注解相关信息applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed &#61; true;}
}
//省略代码...
// AbstractAutowireCapableBeanFactory#doCreateBean 619行
//省略代码...
try {// 这里会将注入对应的属性populateBean(beanName, mbd, instanceWrapper);exposedObject &#61; initializeBean(beanName, exposedObject, mbd);
}
//省略代码...// AbstractAutowireCapableBeanFactory#populateBean 1431行
//省略代码...
// 这里会依次遍历 如果是&#64;Resource会在CommonAnnotationBeanPostProcessor中触发注入
// 如果是&#64;Autowired则会在AutowiredAnnotationBeanPostProcessor中触发注入
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse &#61; bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse &#61;&#61; null) {if (filteredPds &#61;&#61; null) {filteredPds &#61; filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse &#61; bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse &#61;&#61; null) {return;}}pvs &#61; pvsToUse;
}
//省略代码...
上面三个其实类似&#xff0c;同前面三步骤差不多
// AbstractBeanFactory#doGetBean 256行 入口
// DefaultSingletonBeanRegistry#getSingleton 150
// 此时&#xff0c;一级缓存和二级缓存里面都没有&#xff0c;三级缓存在第二步里面放进去了&#xff0c;此时能拿到对应的ObjectFactory&#xff0c;
//通过它可以获取对应的实例。然后将实例放入二级缓存&#xff0c;将三级缓存中对应的BeanName移除
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject &#61; this.singletonObjects.get(beanName);if (singletonObject &#61;&#61; null && isSingletonCurrentlyInCreation(beanName)) {singletonObject &#61; this.earlySingletonObjects.get(beanName);if (singletonObject &#61;&#61; null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject &#61; this.singletonObjects.get(beanName);if (singletonObject &#61;&#61; null) {singletonObject &#61; this.earlySingletonObjects.get(beanName);if (singletonObject &#61;&#61; null) {ObjectFactory<?> singletonFactory &#61; this.singletonFactories.get(beanName);if (singletonFactory !&#61; null) {singletonObject &#61; singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;
}
这里属性注入完后&#xff0c;剩下bean增强、循环依赖校验、注册
DisposableBean
// DefaultSingletonBeanRegistry#getSingleton 259行
//省略代码...
// 这在执行链路的上面几层。这里判断是否是新的单例&#xff0c;如果是则置入缓存(一级缓存)中
if (newSingleton) {addSingleton(beanName, singletonObject);
}
//省略代码...protected void addSingleton(String beanName, Object singletonObject) {
// 放入一级缓存&#xff0c;从二级缓存和三级缓存中移除synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}
逻辑基本同上
&#64;Service
&#64;Slf4j
public class AService {static {log.info("AService init&#61;&#61;&#61;>");}&#64;Resourceprivate BService bService;public String a2bService(){return bService.get();}&#64;Async("async-2")public void exec(){log.info("aService exec");}}
&#64;Service
&#64;Slf4j
public class BService {static {log.info("BService init&#61;&#61;&#61;>");}&#64;Autowiredprivate AService aService;public String get(){return "BService 666";}public void exec(){log.info("BService exec");}}
这里
AService
和BService
在同一个目录下&#xff0c;也没有被在别的类中注入(如果有一个类把两者都注入了&#xff0c;且Bservice
先注入&#xff0c;此时如果三个类中该类最先注入&#xff0c;就会导致Bservice
先初始化)。在这种情况下&#xff0c;默认就会Aservice
先初始化&#xff0c;然后在Bservice
初始化&#xff0c;如此&#xff0c;才能复现问题。
如果想要调整类加载顺序&#xff0c;可以通过&#64;DependsOn(value &#61; "AService")
或者&#64;Lazy
别开启懒加载&#xff0c;不然启动不会报错。
spring.main.lazy-initialization&#61;true
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name &#39;AService&#39;: Bean with name &#39;AService&#39; has been injected into other beans [BService] 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 &#39;getBeanNamesForType&#39; with the &#39;allowEagerInit&#39; flag turned off, for example.at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:649)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)at com.yichen.casetest.CaseTestApplication.main(CaseTestApplication.java:47)
在bean实例后续步骤中&#xff0c;会对bean
增强
// AbstractAutowireCapableBeanFactory#doCreateBean 620行
try {populateBean(beanName, mbd, instanceWrapper);// 初始化bean&#xff0c;对Bean增强// 1、invokeAwareMethods// 2、applyBeanPostProcessorsBeforeInitialization// 3、invokeInitMethods// 4、applyBeanPostProcessorsAfterInitializationexposedObject &#61; initializeBean(beanName, exposedObject, mbd);
}
在
applyBeanPostProcessorsAfterInitialization
中&#xff0c;由于使用了异步线程池(用了&#64;EnableAsync
)&#xff0c;使得AsyncAnnotationBeanPostProcessor
注入了spring
容器&#xff0c;它会为原有的bean
实例创建CGLIB
代理&#xff0c;使得最初的bean
和实例化后暴露出去的bean
不是同一个&#xff0c;没有通过循环引用校验&#xff0c;抛出了异常。
// AsyncAnnotationBeanPostProcessor的子类
//AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization 86行
// 如果类中有&#64;Async会创建代理
if (isEligible(bean, beanName)) {ProxyFactory proxyFactory &#61; prepareProxyFactory(bean, beanName);if (!proxyFactory.isProxyTargetClass()) {evaluateProxyInterfaces(bean.getClass(), proxyFactory);}proxyFactory.addAdvisor(this.advisor);customizeProxyFactory(proxyFactory);// Use original ClassLoader if bean class not locally loaded in overriding class loaderClassLoader classLoader &#61; getProxyClassLoader();if (classLoader instanceof SmartClassLoader && classLoader !&#61; bean.getClass().getClassLoader()) {classLoader &#61; ((SmartClassLoader) classLoader).getOriginalClassLoader();}return proxyFactory.getProxy(classLoader);
}
// AbstractAutowireCapableBeanFactory#doCreateBean 632行
// 循环引用检测
if (earlySingletonExposure) {Object earlySingletonReference &#61; getSingleton(beanName, false);if (earlySingletonReference !&#61; null) {if (exposedObject &#61;&#61; bean) {exposedObject &#61; earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans &#61; getDependentBeans(beanName);Set<String> actualDependentBeans &#61; new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name &#39;" &#43; beanName &#43; "&#39; has been injected into other beans [" &#43;StringUtils.collectionToCommaDelimitedString(actualDependentBeans) &#43;"] in its raw version as part of a circular reference, but has eventually been " &#43;"wrapped. This means that said other beans do not use the final version of the " &#43;"bean. This is often the result of over-eager type matching - consider using " &#43;"&#39;getBeanNamesForType&#39; with the &#39;allowEagerInit&#39; flag turned off, for example.");}}}
}
1、不用异步线程池&#xff0c;自己实现线程池
2、通过&#64;lazy
、&#64;DependsOn
&#xff0c;调整类加载顺序&#xff0c;如果让Bservice
先加载就不会出错
3、梳理业务逻辑&#xff0c;调整技术实现&#xff0c;让AService
和Bservice
不循环引用
Using &#64;Async in a circular dependency will throw a BeanCurrentlyInCreationException