自学内容网 自学内容网

Spring源码-循环依赖

核心流程永:

A创建的时候,发现依赖了B,那就创建B.

B在创建的过程中,需要注入A,那就去单例池找A,如果找不到,那就去creatingSet中找A,如果存在A,那就说明存在循环依赖。判断A需不需要进行AOP,如果需要AOP,那就提前进行AOP;如果不需要,那就返回原始对象。

如果提前AOP,那就创建代理对象,并将创建出来的代理对象放到二级缓存中,二级缓存保证了代理对象只会被创建一次。

三级缓存

  1. singletonObjects 单例池(完整Bean生命周期)
  2. earlySingletonObjects (半成品)早期的单例池(普通对象或者代理对象),存放到是三级缓存执行后的结果
  3. singletonFactory (ObjectFactory)临时存放Lambda表达式<普通对象>,可以生成代理对象,放到二级缓存(生成后就清空)

使用到的核心方法:

1.addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)):三级缓存存放beanName和lambda表达式,lambda表达式存放原始对象,并且通过该lambda表达式可以生成AOP的代理对象

2.getSingleton():找bean--涉及一级缓存、二级缓存、三级缓存

说明:@EnableAOP就是生成一个BeanPostProcessor,然后AOP依赖BeanPostProcessor来生成代理对象

例子:

A a= new A();

a.b = b;

B b = new B();

b.a = a;

说明:

1.A在创建的时候,在属性填充的时候,会调用getSingleton找B,此时B还没有创建,那这个方法就直接返回,去创建B

2.B在属性填充的时候,也会进到这个方法(getSingleton),去一级缓存,二级缓存拿,拿不到就加锁,去三级缓存拿,拿到lambda表达式,执行lambda表达式,拿到A的原始对象或者创建A的代理对象或者,完成B的创建,将B放到单例池。

3.然后A从单例池拿到B,完成后续创建流程。

如果不存在代理的逻辑,那么两级缓存就能解决循环依赖的问题

如果在初始化后要进行AOP,那么就需要在初始化后生成代理对象,如果存在循环依赖的问题,就需要提前进行AOP。

我们怎么知道出现了循环依赖呢?

在一开始就记录了creatingSet<>(正在创建中的bean)

核心代码如下:

// 为了解决循环依赖提前缓存单例创建工厂
// 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));// isSingletonCurrentlyInCreation正在创建中
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
        }
        // 循环依赖-添加到三级缓存
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

1.Lambda表达式的执行

DefaultSingletonBeanRegistry#getSingleton

@Nullable
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();// 执行三级缓存的lambda表达式
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);// 用完 lambda表达式就移除
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

执行lambda表达式,那就会调用getEarlyBeanReference(在类AbstractAutoProxyCreator)

在这个方法中,earlyProxyReferences.put:记录是否进行了AOP,如果进行了AOP,就放到这个Map中

然后调用wrapIfNecessary:判断是否需要AOP,需要就createProxy(创建代理对象)

正常进行AOP的地方(初始化后):AbstractAutoProxyCreator#postProcessAfterInitialization()

如果提前进行了AOP,那么这个方法不会再AOP,直接返回原始对象;之后去二级缓存找到代理对象,完成A的创建。

 

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {// 如果AOP后发现bean发生改变
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

2.几种循环依赖的情况

Enable注解就是生成一个BeanPostProcessor(不完全正确),比如@EnableTransactional没有新生成beanPostProcessor,添加的是Advisor。

2.1@Async会导致暴露的对象改变

if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) { // 如果有些postProcessor直接创建了bean,那这里就不一样
            exposedObject = earlySingletonReference;
        }
        else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            // beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                    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 " +
                       "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
            }
        }
    }
}

(AOP和@Async都存在的情况下,并且存在循环依赖,那就会抛异常)

@Async的大致执行原理:创建代理对象,异步开一个线程去完成操作的。和AOP是不同的

@EnableAsync就会新增一个postProcessor,这个postProcessor在AOP之后执行

Async会生成一个新的代理对象,那么此时exposedObject就发生改变了。这样就会导致赋值给其他Bean的和放到单例池的不是同一个Bean

解决办法:加了lazy注解之后,会给bService直接生成一个代理对象给A赋值。之后真正用到bService的时候,才会去找A,或者创建B的bean,比如这里的test用到bService

说明:A中加Async导致出错,是因为A依赖B,需要创建B,B在创建的时候用到了A的代理对象,赋值给B的这个代理对象和A最终生成的对象(A最终放到单例池的对象)不是同一个,所以报错

说明:把Async写到bService,就不会报错,此时是因为,B需要拿到完整的A,拿到A之后,就可以进行初始化、AOP以及Async,之后会生成完整的B。

2.2两个原型Bean产生的循环依赖

两个都是原型bean,那他们产生的循环依赖没有办法解决;如果只有一个原型Bean,那么不会报错

两个原型bean的原因:他们会 互相 一直创建彼此,导致死循环

2.3实例化使用构造方法产生的循环依赖

解决办法:通过@Lazy注解来解决,Spring会创建一个aService的代理对象来给B的构造方法使用

2.4@Transactional

不会报错,@Transactional因为没有新生成beanPostProcessor,添加的是Advisor,所以最后暴露的对象是同一个

2.5自己注入自己

不会出现问题

执行流程:

1.实例化A,存到三级缓存

2.注入A,先去一级缓存找A,再去二级缓存找A,再去三级缓存找A,此时肯定能找到A(或者是A的普通对象,或者是A的代理对象),那么完成A的注入

3.继续创建,完成A的创建


原文地址:https://blog.csdn.net/m0_45164511/article/details/142720584

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!