Spring中Bean循环依赖详解

1. Bean创建的主要流程

先获取,没有的话再创建,如下图所示

 创建bean的主要流程如下:

  • getSingleton:从容器里面获取单例的bean,没有的话创建
  • doCreateBean:没有就创建bean
  • addSIngletonFactory:将创建bean的 factory 缓存起来
  • populateBean:创建完了以后,要填充属性
  • addSingleton:填充完了以后,再添加到容器进行使用

依赖是在目标对象里,代理对象的字段没有值,如下图所示:

2. 解决循环依赖时需要的缓存

Spring在解决循环依赖时使用了 三级缓存,如果没有代理的话,用一级缓存就可以解决。二三级缓存主要是为了解决代理的生成。

一级缓存(也叫单例池): singletonObjects,存放已经经历了完整生命周期的Bean对象。

二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整),存放半成品的Bean。

三级缓存: singletonFactories,存放可以生成Bean的工厂,主要是解决aop特性,()->getEarlyBeanReference(beanName,mbd,bean),getEarlyBeanReference()返回增强后的bean。

3. 循环依赖具体流程分析

在代码中创建3个Bean,然后相互依赖,再创建切面,让这几个Bean生成代理。

3.1 代码示例

@Component
public class TestA {

    @Autowired
    TestB testB;

    public void test(){
        System.out.println("----aaa----");
    }
}
@Component
public class TestB {

    @Autowired
    TestC testC;

    public void test(){
        System.out.println("----bbb----");
    }
}
@Component
public class TestC {

    @Autowired
    TestA testA;

    public void test(){
        System.out.println("----ccc----");
    }
}

@Aspect
@Configuration
public class TestAspect {


    @Pointcut("execution(* com.shopping.demo24.component.*.test(..))")
    public void pointcut() {}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(this.getClass().getSimpleName()+"-around:before");
        Object result=joinPoint.proceed();
        System.out.println(this.getClass().getSimpleName()+"-around:after");
        return result;
    }

}

3.2 调试分析

1. 获取a->创建a->将a添加到singletonFactories->设置依赖b->获取b

2. 创建b->将b添加到singletonFactories->设置依赖c开始->获取c

3.创建c->将c添加到singletonFactories

此时缓存池中的 bean 如下,没有写的为空

singletonFactories:a, b, c

 4. 给c设置依赖a开始->获取a

先从singletonObjects中获取,没有,再从earlySingletonObjects中获取,也没有,最后在singletonFactories的ObjectFactory中获取。获取以后添加到earlySingletonObjects中,这里面的a是增强后的a,但是依赖的属性没有设置。再从singletonFactories中删除

此时

earlySingletonObjects: a

singletonFactories: b,c

 ObjectFactory的值为 () -> getEarlyBeanReference(beanName, mbd, bean)

 从ObjectFactory获取时会对a调用BeanPostProcessor的getEarlyBeanReference()返回增强后的a

 

 包装对象,生成代理

 a 在这里增强后,在后面的postProcessAfterInitialization()方法中,创建代理对象(增强对象)的AbstractAutoProxyCreator中如果有对应的earlyProxyReferences记录(这里的记录不是增强对象,而是原始对象),就不会再被增强。

 

 5. 通过反射,给c设置依赖

给c设置依赖a结束,调用initializeBean()方法,生成代理对象,创建完c,将c添加到singletonObjects中,删除earlySingletonObjects和singletonFactories中的对应值。

 此时

earlySingletonObjects:a

singletonFactories: b

singletonObjects: c

6: 给b设置依赖c结束,调用initializeBean()方法,生成代理对象, 创建完b,将b添加到singletonObjects中b是代理对象

earlySingletonObjects:a

singletonFactories: null

singletonObjects: b,c

7: 给a设置依赖b完成

此时,对于 a, 调用initializeBean()方法返回的不是增强对象,

 

因为earlyProxyReferences中存在a,表示它已经被增强过

 获取earlySingletonObjects中的a,这里的a是增强对象。

创建完a,将a添加到singletonObjects中

earlySingletonObjects:null

singletonFactories: null

singletonObjects: b,c,a

至此,a,b,c 三个bean创建完成,也都加到了 singletonObjects 中,其他两个缓存池都为空。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值