关于对spring注入bean的顺序,以及spring如何保证事先加载依赖bean的问题

本文详细解析了Spring如何处理bean的循环依赖,特别是通过三级缓存来解决这一问题。介绍了bean的实例化和初始化的区别,并讨论了Spring为何需要三级缓存而非二级缓存。此外,文章探讨了构造器循环依赖无法解决的原因以及解决循环依赖的策略,如延迟加载。最后,文章提及代理对象在循环依赖中如何确保返回的是代理对象。

一直对spring容器中注入依赖有一个疑问:当Abean有一个属性Bbean,即Abean对Bbean有依赖,那么容器是怎么保证Bbean在Abean之前加载呢?

在说这个问题答案之前,我先抛出一个问题,什么是bean的实例化,什么是bean的初始化,当Abean进行实例化的时候,是对于依赖的Bbean需要的是初始化还是实例化?

这个问题困扰了我很久,困扰的原因是spring的后置工厂处理器(beanPostProcesser)对bean实例化和初始化的定义让我先入为主,弄得我混淆了spring与java类的实例化和初始化的定义

这里我只说spring对bean实例化和初始化的定义,java类的实例化和初始化定义请看我的另一篇博客:java 类生命周期详解 以及初始化和实例化的区别好的,废话不多说,直接给答案:
bean实例化:是bean对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。
bean初始化:是为对象中的属性赋值的过程。
如图:
在这里插入图片描述

然后,前面那个问题,当Abean进行实例化的时候,是对于依赖的Bbean需要的是是实例化,而不是初始化。
在这里插入图片描述
这里我们以上面的首先初始化A对象实例为例进行讲解整个过程。先说明:基于构造器的循环依赖spring是无法解决的。

首先Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例,由于Spring容器中还没有A对象实例,因而其会创建一个A对象

然后发现其依赖了B对象,因而会尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例

但是Spring容器中此时也没有B对象的实例,因而其还是会先创建一个B对象的实例。

读者需要注意这个时间点,此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去。(初始化)

在前面Spring创建B对象之后,Spring发现B对象依赖了属性A,因而还是会尝试递归的调用ApplicationContext.getBean()方法获取A对象的实例

因为Spring中已经有一个A对象的实例,虽然只是半成品(其属性b还未初始化),但其也还是目标bean,因而会将该A对象的实例返回。

此时,B对象的属性a就设置进去了,然后还是ApplicationContext.getBean()方法递归的返回,也就是将B对象的实例返回,此时就会将该实例设置到A对象的属性b中。

这个时候,注意A对象的属性b和B对象的属性a都已经设置了目标对象的实例了

读者朋友可能会比较疑惑的是,前面在为对象B设置属性a的时候,这个A类型属性还是个半成品。但是需要注意的是,这个A是一个引用,其本质上还是最开始就实例化的A对象。

而在上面这个递归过程的最后,Spring将获取到的B对象实例设置到了A对象的属性b中了

这里的A对象其实和前面设置到实例B中的半成品A对象是同一个对象,其引用地址是同一个,这里为A对象的b属性设置了值,其实也就是为那个半成品的a属性设置了值。

三级缓存

Spring能够轻松的解决属性的循环依赖正式用到了三级缓存,在DefaultSingletonBeanRegistry 中,有着3个map

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
    //用来顺序存储beanName
 	private final Set<String> registeredSingletons = new LinkedHashSet(256);
 	//当bean处于创建时期,会放入此中,用来判断循环依赖
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
    private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap(16));
   ....}

1、singletonObjects 它是我们最熟悉的朋友,俗称“ 单例池 ”“ 容器 ”,缓存创建完成单例Bean的地方。

2、singletonFactories 映射创建Bean的原始工厂,注意,这个是工厂map

3、earlySingletonObjects 映射Bean的 早期 引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“ Bean ”,只是一个 Instance .

整个流程看个git图:
在这里插入图片描述
在这里插入图片描述

看源码之前,要说的是正常的获取bean是AbstractBeanFactory的getBean方法,他会调用到DefaultSingletonBeanRegistry 的getSingleton(俩个都会调用),但这只是第一步,之后还有doCreateBean方法等

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

         // 方法1)从三个map中获取单例类
        Object sharedInstance = getSingleton(beanName);//这个getSingleton对应了DefaultSingletonBeanRegistry 第一个getSingleton方法,该方法在类里有俩个重载
        // 如果sharedInstance 不为空(第一次取自然为空,不为空则代表不是第一次取,代表有循环依赖)
        if (sharedInstance != null && args == null) {
            if (this.logger.isTraceEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }

            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        }
        //否则如果为空,进入主题:
        else {
            // 如果是多例的循环引用,则直接报错
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            // 省略若干无关代码
            try {
                // Create bean instance.
                if (mbd.isSingleton()) {
                    // 方法2) 获取单例对象,第二个getSingleton方法,该方法在类里有俩个重载,该方法本身其实实现了俩个方法,一个是参数方法,一个是自身
                    sharedInstance = getSingleton(beanName, () -> {
                        try { //方法3)
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
         }
        // 省略若干无关代码
        return (T) bean;
    }

第一次getSingleton,三个缓存里都没有,返回了空

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 检查一级缓存singletonObject是否存在
	Object singletonObject = this.singletonObjects.get(beanName);
	
	// 当前还不存在这个单例对象,
	// 且该对象正在创建中,即在singletonsCurrentlyInCreation列表中
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
		
		    // 检查二级缓存earlySingletonObjects是否存在
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
			
			    // 检查三级缓存singletonFactory是否可以创建,如果存在循环依赖,则会有实例
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
				
				    // 三级缓存的对象工厂创建该对象,这个方法利用了反射,调用了AbstractAutowireCapableBeanFactory的getEarlyBeanReference方法的(切面),保证了扩展性
					singletonObject = singletonFactory.getObject();
					
					// 放入二级缓存earlySingletonObjects中
					this.earlySingletonObjects.put(beanName, singletonObject);
					
				    // 移除一级缓存
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}


//在AbstractAutowireCapableBeanFactory类doCreateBean方法中有getObject方法实现了继承
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) {
    
 ......省略代码
            this.addSingletonFactory(beanName, new ObjectFactory<Object>() {
                public Object getObject() throws BeansException {
                    return                   
AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }
        ....省略代码
}


protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (bean != null && !mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Iterator i$ = this.getBeanPostProcessors().iterator();

            while(i$.hasNext()) {
                BeanPostProcessor bp = (BeanPostProcessor)i$.next();
                //切面SmartInstantiationAwareBeanPostProcessor类
                //一般情况下,如果系统中没有SmartInstantiationAwareBeanPostProcessor接口;就是直接返回exposedObject什么也不做; 
//.所以利用SmartInstantiationAwareBeanPostProcessor可以改变一下提前暴露的对象;
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return exposedObject;
                    }
                }
            }
        }

        return exposedObject;
    }

重载
到了第二个getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                // 判断,并首次将beanName即teacher放入singletonsCurrentlyInCreation中
                beforeSingletonCreation(beanName); // 步骤A
                boolean newSingleton = false;
                // 省略无关代码
                try {
                //与第一个singleton同样的切面
                    singletonObject = singletonFactory.getObject();// 步骤B
                    newSingleton = true;
                }
                // 省略无关代码
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    afterSingletonCreation(beanName);// 步骤C 得到单例对象后,再讲beanName从singletonsCurrentlyInCreation中移除
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);// 步骤D
                }
            }
            return singletonObject;
        }
    }
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, singletonObject);//添加单例对象到map中
            this.singletonFactories.remove(beanName);//从早期暴露的工厂中移除,此map在解决循环依赖中发挥了关键的作用
            this.earlySingletonObjects.remove(beanName);//从早期暴露的对象map中移除
            this.registeredSingletons.add(beanName);//添加到已注册的单例名字集合中
        }
    }

重点来了!!!!!!!!!!!!!!!
别搞混了,这里说的是文章最开头createBean方法里的
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
这里然后会调用AbstractAutowireCapableBeanFactory的createBean方法,我们认真看下这个createBean方法,会调用AbstractAutowireCapableBeanFactory的doCreateBean方法,doCreateBean的方法实现如下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        BeanWrapper instanceWrapper = null;
        // 省略代码
        if (instanceWrapper == null) {
            // 实例化bean,这里其实已经实例化bean了,记住了这个bean instanceWrapper ,后面是解答疑惑的关键
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //看到这里,它将instanceWrapper 赋值给了名为bean的bean
final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
        Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                mbd.postProcessed = true;
            }
        }
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            // 重点!!!将实例化的对象添加到singletonFactories中,该方法addSingletonFactory为DefaultSingletonBeanRegistry类下的,而参数getEarlyBeanReference方法则为当前类下,注意这里的参数bean即是(第一步实例化的instanceWrapper,赋值给了名为bean的bean)
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
        // 初始化bean
        Object exposedObject = bean;
        try {
        // 2.依赖注入,即 setXX(@Autowird的bean)
            populateBean(beanName, mbd, instanceWrapper);
             // 3.spring对这个bean对象进行一些初始化操作:applyBeanPostProcessorsBeforeInitialization(初始化前置回调)、invokeInitMethods(初始化方法)、applyBeanPostProcessorsAfterInitialization(初始化后置回调)。init-method方法的执行。
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        // 省略无关代码
        return exposedObject;
}

//DefaultSingletonBeanRegistry类下
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);
            }

        }
    }
    
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        //aop切面开始,拿到InstantiationAwareBeanPostProcessors的所有实现类
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Iterator var5 = this.getBeanPostProcessors().iterator();

            while(var5.hasNext()) {
                BeanPostProcessor bp = (BeanPostProcessor)var5.next();
                //如果是SmartInstantiationAwareBeanPostProcessor类,进行切面函数执行
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
                    //SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }

        return exposedObject;
    }
//SmartInstantiationAwareBeanPostProcessor,
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        return bean;
    }


关于最后 getEarlyBeanReference()方法我是存在疑问的,因为按道理说应该返回的是objectFacroty实例作为addSingletonFactory方法的第2个参数,但是最后返回的bean好像就只是一个bean,按我的理解应该是返回objectFacroty<beanName,bean>这样的东西。因为看到后面执行的话,拿到返回的objectFacroty.getObject方法才是bean,问题暂时先放这

属性注入主要是在populateBean方法中进行的。对于循环依赖,以我们假设中的Teacher中注入了Student、Student中注入了Teacher为例来说明,假定Spring的加载顺序为先加载Teacher,再加载Student。

getBean方法触发bean的初始化后:

a. 首先走到doGetBean中的方法1),此时map中都为空,获取不到实例;

b. 然后走到方法2getSingleton)中,步骤A、步骤C、步骤D为控制map中数据的方法,实现简单,可暂不关注。其中步骤B的getObject方法触发对方法3)的调用;

c. 在方法3)中,先通过createBeanInstance实例化Teacher对象,又将该实例化的对象通过addSingletonFactory方法放入singletonFactories中,完成Teacher对象早期的暴露;

d. 然后在方法3)中通过populateBean方法对Teacher对象进行属性的注入,发现它有一个Student属性,则触发getBean方法对Student进行初始化

e. 重复a、b、c步骤,只是此时要初始化的是Student对象

f. 走到d的时候,调用populateBean对Student对象进行属性注入,发现它有一个Teacher属性,则触发getBean方法对Teacher进行初始化;

g. 对Teacher进行初始化,又来到a,但此时map已经不为空了,因为之前在c步骤中已经将Teacher实例放入了singletonFactories中,a中得到Teacher实例后返回;

h.完成f中对Student的初始化,继而依次往上回溯完成Teacher的初始化;

完成Teacher的初始化后,Student的初始化就简单了,因为map中已经存了这个单例。
在这里插入图片描述

如果通过属性值或者setter方法注入,则没有循环依赖问题。因为主bean和所依赖的bean都可以成功调用构造函数创建对象,通过对象引用来引用对方。属性值注入和setter方法注入,通过bean对象的后置处理器BeanPostProcessor来对该bean对象的属性值进行注入;
如果该依赖bean对象通过构造函数注入主bean对象,则在调用构造函数创建该依赖bean对象,需要查找主bean对象时,查找时会继续调用到AbstractBeanFactory的doGetBean方法获取主bean对象,而在AbstractBeanFactory的doGetBean方法调用getSingleton方法检查三级缓存是否可以得到主bean对象。
由步骤1和步骤2可知,由于getSingleton方法的singletonsCurrentlyInCreation和singletonFactories都已经有了主bean的相关信息,通过三级缓存可以查找到主bean对象,即通过主bean对象的创建工厂singletonFactories创建提前曝光的主bean对象,并放入二级缓存earlySingletonObjects,故可以解决为这个依赖bean对主bean的依赖注入,从而成功创建该依赖对象bean。

为什么Spring不能解决构造器的循环依赖?
在Bean调用构造器实例化之前,一二三级缓存并没有Bean的任何相关信息,在实例化之后才放入三级缓存中,因此当getBean的时候缓存并没有命中,这样就抛出了循环依赖的异常了。
如下controller为主bean,service为所依赖的bean:

为什么多实例Bean不能解决循环依赖?
非单例的每次创建都是new一个对象,IOC不会对其进行缓存,如果AB循环依赖,那么创建A1的时候依赖B1,然后要创建B1的时候发现依赖A,由此再去创建A2,然后A2有需要一个B2,一直下去没有尽头。不过Spring在代码中是有判断的,在AbstractBeanFactory的doGetBean中,如果缓存中获取Bean失败,就会判断需要获取的Bean是否为处于创建中的原型Bean,如果是就会抛出异常

如何解决构造器的循环依赖?
延迟加载lazy-initial

为什么有三级缓存不是二级缓存?

二级缓存可以解决这个问题吗?其实二级缓存是可以解决这个问题的,但是前面说了三级缓存的目的是将返回早起引用对象这个动作给用于预留一个扩展接口,在三级缓存中获取Bean调用的getEarlyBeanReference会回调SmartInstinationBeanPostProcessor这个接口的方法,开发者可以在这个阶段对返回的Bean对象做修改,如果AB循环依赖,B就会调用getEarlyBeanReference获取A,从而B会从三级缓存得到一个扩展后的A,并移动到二级缓存。
换个角度假如只有2级缓存,那么用户扩展的动作就要放到二级缓存()来做,这样每一次来获取的时候如果一级缓存没有都需要在二级缓存执行一次singletonFactory.getObject(singletonFactorys)触发一下获取Bean,这样这个方法很可能会被执行多次,每次都会从singletonFactorys找到该beanFactory去反射创建一个新的对象,由此肯定会引起问题,引入了三级缓存singletonFactory.getObject()只会在第一次获取的时候,前两级缓存都不存在才会触发一次,并立刻将自己放到二级缓存,并清空三级缓存,后面每一次获取的都是这次创建的这个对象。
如果不需要扩展,放进去的早期引用就是不完整的Bean,不考虑给其他后置处理器扩展,这样使用2级缓存是可以的。A直接将自己放入二级缓存,循环依赖的时候B直接从二级缓存获取A的早期引用保证B初始化成功再将自己加到一级缓存,然后A初始化成功后添加到一级缓存,但是这样就不能扩展了,因为这个扩展点很重要,在AOP的AnnotationAwareAspectJAutoProxyCreator就通过这个扩展点来保证代理对象的返回和代理对象的循环依赖问题解决(保证循环依赖的时候,返回的对象也是代理对象)
综上来看三级缓存的目的是预留一共扩展接口,而这个接口和AOP有关。

如果一个代理对象被循环依赖,如何保证最后返回到IOC的是代理对象?

1.首先A初始化,然后在构造函数实例化之后,属性填充的时候,发现需要B,因此进入初始化B的流程;
2.初始化B,也和A前面一样,发现需要A就去获取A,获取A的时候,去三级缓存查询,第三级查到了,并且会调用getEarlyBeanReference,而getEarlyBeanReference会触发AOP中
核心类的父类AbstractAutoProxyCreator的getEarlyBeanReference执行,在这里会返回A的一个代理对象,由此B获得了A,B初始化成功
@Override
	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			this.earlyProxyReferences.add(cacheKey);
		}
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

3.回到A的初始化过程,A得到一个B对象,B进行属性填充,初始化,

最后,还有一点没太弄懂,我始终没找到,从singletonFactories 找到bean并放入earlySingletonObjects的代码,这个 earlySingletonObjects在代码里一直先于singletonFactories 找bean,但是这个bean是什么时候存进去的呢,找不到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值