spring源码---@Async导致循环依赖失效的原因分析

上一篇文章spring循环依赖下使用@Async注解导致报错问题提出了@Async导致spring循环依赖失效的问题,今天这篇文章就重点分析原因;里面涉及到spring的源码相关的知识,比较复杂;

案例:

先上测试代码:

1.创建schoolService,注入studentService;

@Service
public class SchoolService {

    @Autowired
    private StudentService studentService;

    @Async
    public void updateSchool(){
       ...
    }
}

2.创建studentService,注入schoolService

@Service
public class StudentService {

    @Autowired
    private SchoolService schoolService;

}

3.启动服务,前提是spring先加载的schoolService,就会报错如下:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'schoolService': Bean with name 'schoolService' has been injected into other beans [studentService] 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.

分析原因:

1.定位到具体代码:

AbstractAutowireCapableBeanFactory类的doCreateBean方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        

        if (instanceWrapper == null) {
            //创建对象,利用反射new一个具体对象
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        
       //earlySingletonExposure为true     isSingleton是否单例,为true;allowCircularReferences是否允许循环依赖,默认就为true;isSingletonCurrentlyInCreation为true
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            

            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
            //对schoolService进行属性注入,包括注入StudentService
            this.populateBean(beanName, mbd, instanceWrapper);
            //对schoolService进行初始化,这个里面会调用@Async这个注解对应的处理器,生成一个schoolService动态代理对象exposedObject
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            ......
        }

        //earlySingletonExposure为true
        if (earlySingletonExposure) {
            
            //从二级缓存earlySingletonObjects中获取到schoolService的对象,还不是bean;
            Object earlySingletonReference = this.getSingleton(beanName, false);
            if (earlySingletonReference != null) {

                //由于exposedObject是经过动态代理的,所以和bean不同
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {

                    //getDependentBeans就是获取自己依赖的对象,是studentService;
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            //由于依循环赖的studentService已经创建好了,所以会被添加进去
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    //actualDependentBeans不为空,报错
                    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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

2.分析:循环依赖的流程图如下图所示:

1.首先加载schoolService,尝试从一级缓存获取,没有;

2.检查是作用域是单例isSingleton,将bean标记为正在创建,

        2.1调用createBean--》doCreateBea方法开始创建bean;

        2.2 doCreateBea里面先利用反射创建SchoolService普通对象,然后将其放入三级缓存singletonFactories;beanName为key,value是lambda表达式,里面会判断是否执行处理器,进行AOP动态代理;

        2.3  执行populateBean方法属性注入studentService;但是我们的studentService还没有,所以就会创建studentService;

        2.3.1  创建studentService;按照上面的顺序-----》执行到populateBean的时候,studentService就会注入schoolService;

        2.3.2  调用getSingleton方法,获取到schoolService的早期对象;

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        
        //尝试从一级缓存/单例池获取,没有,因为schoolService还只是一个对象,不是bean
        Object singletonObject = this.singletonObjects.get(beanName);

        //schoolService在首次创建的时候是被标记为正在创建,所以isSingletonCurrentlyInCreation为true
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {

                //从二级缓存获取,还是没有,
                singletonObject = this.earlySingletonObjects.get(beanName);
                
                //allowEarlyReference为true,
                if (singletonObject == null && allowEarlyReference) {
        
                    //从三级缓存获取到,并执行lambda表达式获取到schoolService对象,并将该对象放入二级缓存,从三级缓存删除,避免重复创建
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }

        2.3.4 studentService成功获取到schoolService的早期对象,完成了属性注入,然后执行初始化方法完成 studentService的bean创建;创建完成返回到如下代码

上面的代码成功创建了studentService,并且将其放入单例池完成bean的创建;

我们回到schoolService的populatBean方法那里去;

2.4  执行schoolService的初始化方法;在这个方法里面,会执行async的处理器,AsyncAnnotationBeanPostProcessor 它是一个 BeanPostProcessor,实现了 postProcessAfterInitialization 方法,也就是在初始化后期执行;这里为schoolService生成一个代理对象;

2.5  初始化执行完毕:执行下面的判断代码会报错;

//earlySingletonExposure为true
if (earlySingletonExposure) {

            //getSingleton方法从二级缓存获取schoolService的早期对象
            Object earlySingletonReference = this.getSingleton(beanName, false);

            if (earlySingletonReference != null) {
                //exposedObject是初始化后的,由于@Async生成了一个代理对象,所以下面的判断为false
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;

                //下面的判断,hasDependentBean里是判断schoolService的循环依赖的bean有没有,schoolService和studentService是循环依赖,所以为true
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {

                    //获取schoolService的循环依赖studentService
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];

                        //removeSingletonIfCreatedForTypeCheckOnly就是判断schoolService循环依赖的对象studentService是不是已经创建成功了,如果创建成功了,肯定就不合理了
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

                            //放入actualDependentBeans;
                            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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

总结:

由于循环依赖,如果一个bean提供给其它bean依赖的对象和自己本身的对象不同,肯定就不合理了,比如schoolService给循环依赖studentService的属性是注入是一个普通对象,但是给其它bean,不是循环依赖的是动态代理的对象,这样如果我在studentService里面调用schoolService的异步方法,由于不是动态代理的对象,所以该方法也就不会是异步的,但是其它不是循环依赖的bean对象里面调用schoolService的异步方法又是异步;这样就不合理了;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wait疯man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值