在说明循环依赖之前,这里有必要先看一下spring的bean的创建过程。
spring中bean的创建过程
使用AnnotationConfigApplicationContext创建上下文,在refresh()方finishBeanFactoryInitialization方法会将beanDefinitionNames中的bean名称依次创建bean

getBean方法会通过反射的方式new一个bean对应的类(实例化),然后会将依赖的类注入,最后完成初始化,同时这个bean对象会被放入singletonObjects的这个ConcurrentHashMap中,
一个bean的创建就完成了。这个核心方法是在AbstractAutowireCapableBeanFactory的doCreateBean方法中。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 实例话,通过反射创建一个空对象。
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
...
...
...
// 将半成品放入缓存,解决循环依赖
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 装载bean这里会完成依赖的注入
populateBean(beanName, mbd, instanceWrapper);
// *初始化bean,并且在这里判断该bean是否被aop代理,如果被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);
}
}
...
...
...
return exposedObject;
}
在instanceWrapper.getWrappedInstance()完成实例化,populateBean()完成依赖注入,initializeBean()完成初始化和aop代理类的生成。
循环依赖问题的产生
在populateBean的过程中,如果依赖的一个bean还未被创建,则会执行getBean方法创建一个bean。假设serviceA依赖serviceB,serviceB又依赖serviceA。serviceA执行populateBean的时候发现serviceB还没有被创建则取创建serviceB,这时serviceB又在populateBean的过程中发现需要创建serviceA,这样就进入了死循环,就发生了循环依赖的问题。那如何解决循环依赖呢,接下来就进入正题。
spring是如何解决循环依赖问题的
每一个bean会经过实例化和依赖注入以及初始化三步,在实例化后依赖注入之前,先将自己刚实例化的bean缓存,即我们常说的半成品的bean。如果有其他bean在创建时发现需要这个bean则会先从缓存中获取到这个半成品先注入,随后半成品bean随着自己依赖注入以及初始化最终完成一个完整的bean。
在上面的doCreateBean源码中,createBeanInstance实例化之后将空对象(半成品)放入缓存中addSingletonFactory()
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
创建bean之前的doGetBean都会先去缓存中查看是否已经创建好了,在getSingleton方法中
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else{
...
...
...
}
}
重点看getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
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;
}
singletonObjects、earlySingletonObjects、singletonFactories就是所谓的三级缓存,其实也是三个ConcurrentHashMap。
singletonObjects是一级缓存,保存创建完成的单例bean。我们重点关注二级缓earlySingletonObjects和三级缓存singletonFactory,一级缓存可以进行忽略。
从代码逻辑中可以看出,先从一级缓存中查找,一级缓存中没有的话再从二级缓存中找,二级缓存中没有的话会去三级缓存singletonFactories中查找,singletonFactories存放的是目标对象的ObjectFactory,也就是说将一个创建工厂放入缓存中。singletonFactory.getObject()最终会调用getEarlyBeanReference()方法,getEarlyBeanReference方法大致是如果这个bean被AOP切面代理则返回一个代理对象,如果没有则返回原bean实例。从三级缓存中获取到bean后会将该bean的三级缓存删除,随后放入二级缓存中。
示例:
创建一个bean依赖一个被aop代理的bean
@Component
public class ZtestComp {
@Autowired
private TestService testService;
}
@Component
public class TestService{
@Autowired
private ZtestComp ztestComp;
public void query() {
System.out.println("testService do query");
}
}
@Aspect
@Component
public class TestAspect {
@Pointcut("execution(* ww.com.growup.spring.ioc.circleinjectdemo.*.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void advice(){
System.out.println("aop before---");
}
}
@Configuration
@ComponentScan("ww.com.growup.spring.ioc.circleinjectdemo")
@EnableAspectJAutoProxy
public class AnnotationDependencyInjectionResolutionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
applicationContext.setAllowCircularReferences(true);
applicationContext.refresh();
TestService i = (TestService) applicationContext.getBean("testService");
i.query();
applicationContext.close();
}
}
maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.17</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.bundles</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8_2</version>
</dependency>
上图案例中,会先创建testService,实例化后将AbstractAutowriteCapableBeanFactory放入singletonFactory,并传入了testService的BeanDefinition以便后续创建bean提供相应的元数据信息。


在创建testService的过程中发现要注入ztestComp,这时会调用getBean,atestComp的bean还未被创建,就会调用doCreateBean创建atestComp。

在ztestComp的装载bean的过程中发现需要注入testService,则又会去调用doGetBean获取testService,这时在getSingleton中就会从三级缓存中拿出一个testService的ObjectFactory调用singletonFactory.getObject()方法创建一个testService的代理类。

我们可以看到,singletonFactory.getObject()返回的是一个TestService的CGLB代理类。然后将这个代理类的半成品放入二级缓存中,删除一级缓存,如果有其他的bean依TestService的话就直接从二级缓存中取即可。
ztestComp获取到testService的半成品之后继续做其他的依赖注入和初始化完成ztestComp bean的创建,ztestComp创建完成后,testService中对于ztestComp的依赖注入也告一段落了,testService继续将半成品完成其他的依赖注入和初始化。这样testService和ztestComp的循环依赖也算解决完了。
为什么要三级缓存而不是二级缓存呢?
那么这里有人会问了,那为啥不直接创建aop代理的半实例bean放入二级缓存中,不要三级缓存呢。但是前面的bean的创建过程中可以看出,bean创建aop代理对象是在populateBean装载bean之后的initializeBean方法中创建的,所以如果这个bean没有被aop代理的话二级缓存足矣,但是如果被aop代理的话在刚实例化后时还未能创建aop,所以只好将创建bean的工厂放入等需要创建bean的时候再调用工厂的创建bean的方法。
关于aop的bean创建的流程可以看这篇《spring aop源码解析,带你了解aop流程》
本文详细介绍了Spring中bean的创建步骤,包括实例化、依赖注入和初始化,以及在创建过程中如何利用三级缓存解决循环依赖问题。在遇到循环依赖时,Spring会先将半成品bean存入缓存,确保在依赖注入时能正确处理。此外,还探讨了为什么需要三级缓存,特别是对于AOP代理bean的处理。通过实例展示了循环依赖的具体解决过程。
1985

被折叠的 条评论
为什么被折叠?



