spring循环依赖

以下文字全是自己一步一步debug后手打的总结,仅供自己以后复习使用,不敢保证全对,如有错误,欢迎指出。

前置环境:为了更好地理解和debug我这里每个service里面注入了2个service

@Component
public class AService {
    @Autowired
    private BService bService;
    @Autowired
    private CService cService;

    public AService(){
        System.out.println("AService构造函数");
    }
}


@Component
public class BService {
    @Autowired
    private AService aService;
    @Autowired
    private CService cService;

    public BService(){
        System.out.println("BService构造函数");
    }
}


@Component
public class CService {
    @Autowired
    private AService aService;
    @Autowired
    private BService bService;

    public CService(){
        System.out.println("CService构造函数");
    }
}

A第一次getSingleton会先去singletonObject获取bean,没有且isSingletonCurrentlyInCreation判断是否被标记为正在创建,没有被标记则返回一个null
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {


会经过一系列验证比如父子容器 dependsOn等


第二次执行有拉姆达表达式的getSingleton,里面又会尝试去获取bean    Object singletonObject = this.singletonObjects.get(beanName); 
没有获取到则执行 beforeSingletonCreation 去添加 singletonsCurrentlyInCreation 标记为正在创建,此时singletonsCurrentlyInCreation内只有了A数据


接着执行拉姆达表达式回调方法singletonObject = singletonFactory.getObject(); -> return createBean(beanName, mbd, args); ->doCreateBean

接着实例化bean ,Object bean = instanceWrapper.getWrappedInstance();后 java bean已经产生,但内部属性还没有注入

接着因为earlySingletonExposure为true 会将这个拉姆达表达式添加进singletonFactory(三级缓存)    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

populateBean中会执行对于A中的依赖的bean B(@AutoWired)进行getBean(B).


----------------开始重复操作----------------


调用链:AutowiredAnnotationBeanPostProcessor.postProcessProperties -> metadata.inject(bean, beanName, pvs); -> element.inject(target, beanName, pvs); -> beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); -> instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); -> return beanFactory.getBean(beanName); -> B第一次getSingleton会先去singletonObject获取bean,没有且isSingletonCurrentlyInCreation判断是否被标记为正在创建,没有被标记则返回一个null。 
element.inject(target, beanName, pvs);这一步是在循环体内执行的,循环的A所有的依赖


经过一系列验证比如父子容器 dependsOn等

第二次执行有拉姆达表达式的getSingleton,里面又会尝试去获取bean    Object singletonObject = this.singletonObjects.get(beanName); 
没有获取到则执行 beforeSingletonCreation 去添加 singletonsCurrentlyInCreation 标记为正在创建 ,此时singletonsCurrentlyInCreation内有了2条A和B数据

接着执行拉姆达表达式回调方法singletonObject = singletonFactory.getObject(); -> return createBean(beanName, mbd, args); ->doCreateBean

接着实例化bean ,Object bean = instanceWrapper.getWrappedInstance();后 java bean已经产生,但内部属性还没有注入

接着因为earlySingletonExposure为true , addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 会将这个拉姆达表达式添加进singletonFactory(三级缓存)    


1.populateBean中会循环依赖发现了有依赖的bean A(@AutoWired)进行getBean(A).   
element.inject(target, beanName, pvs);这一步是在循环体内执行的,循环的B所有的依赖


此时Object sharedInstance = getSingleton(beanName);发生了变化

singletonObjects没A
isSingletonCurrentlyInCreation对A = true
earlySingletonObjects没A
allowEarlyReference = true
singletonFactories有A的工厂 此时就去调用工厂内部的ObjectFactory.getObject 生产一个A(回调当时加入工厂时的方法getEarlyBeanReference,

此处回答了为何要使用工厂三级缓存:

在此处会循环所有的后置处理器,当中会执行aop的后置处理器返回一个代理对象,如果没有三级工厂,二级中存放的只是普通的A,如:A与B都实现了切面,AB相互依赖,A实例化完成后存到二级缓存(注:当前是模拟没有三级缓存的情况),开始populateBean,发现依赖B,B开始实例化,使用二级缓存中的A,B完成流程,封装成代理对象返回,A再将代理后的B注入,之后执行aop后置处理器,返回A的代理对象,此时A代理对象中的属性B是B代理对象,但是B代理对象中的A却是普通的A。

顺便说明二级缓存的作用,分离半成品和完全体bean,除不能处理aop代理对象外,如果多线程下获取获取一个bean,可能会有线程只能获取到半成品的情况。

执行完后置处理器的返回值就已经成为了一个代理对象(Bean有接口使用的jdk动态代理,否则使用的cglib)

),但此时的A也只是一个java bean,并没有成为一个sping bean,半成品。
最后把生产出来的A放入earlySingletonObjects,再把A的工厂从singletonFactories中移除,此时只有B的工厂在三级缓存。

2.发现还有B一个依赖C,则C也去跑一遍,(populateBean之前加入了工厂三级缓存)当C跑到populateBean时,发现依赖了A则又去getBean(A),getSingleton(beanName),此时又有所不同,因为有一个半成品A已经在前面放入了earlySingletonObjects,工厂中那个已经被移除所以:

singletonObjects没A
isSingletonCurrentlyInCreation对A = true
earlySingletonObjects有A 直接return这个半成品A
    
    C又发现依赖了B,又去getBean(B),则会触发和前面A半成品产生的操作
    singletonObjects没B
    isSingletonCurrentlyInCreation对B = true
    earlySingletonObjects没B
    allowEarlyReference = true
    singletonFactories有B的工厂 此时就去调用工厂内部的ObjectFactory.getObject 生产一个B,但此时的B也只是一个java bean,并没有成为一个sping bean,半成品。
    最后把生产出来的B放入earlySingletonObjects,再把B的工厂从singletonFactories中移除, 此时只有C的工厂在三级缓存。

    C完成

    A最后发现还有一个C,执行C的流程,C会发现依赖了A和B,则去getBean(A)和getBean(B),但是都在二级缓存earlySingletonObjects中获取到了A和B的半成品,最后A完成B、C的属性注入,至此全部完成。

最后在addSingleto()中添加到一级缓存singletonObject,清除2级缓存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值