概念
多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于c、c依赖于A。通常来说,如果问spring容器内部如何解决循环依赖, 一定是指默认的单例Bean中,属性互相引用的场景。
关于循环依赖,Spring官网说明如下,官网地址:docs.spring.io/spring-fram…
官网的结论 :我们AB循环依赖问题只要A的注入方式是 setter且singleton , 就不会有循环依赖问题。
代码演示
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public A() {
System.out.println("对象a的构造方法执行..............");
}
}
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public B(){
System.out.println("对象b构造方法执行........");
}
}
applicationContext.xml配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="a" class="com.luban.service.A" >
<property name="b" ref="b"/>
</bean>
<bean id="b" class="com.luban.service.B">
<property name="a" ref="a"/>
</bean>
</beans>
测试类如下:
public class Test {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
A a = ac.getBean("a", A.class);
B b = ac.getBean("b", B.class);
}
}
三级缓存
通常所说的三级缓存就是指的是在类DefaultSingletonBeanRegistry中三个Map容器,如下:
//这个就是微观springioc容器 【重点三级缓存中的一级缓存,即单例池】
//存放了已经经历了完整生命周期的Bean对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
//【三级缓存】
// 存放可以生成Bean工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
//【二级缓存】
//存放早期暴露出来的Bean对象,Bean生命周期未结束(属性还未填充完)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
- 第一级缓存〈也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象
- 第二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)
- 第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂
循环依赖解决过程如下 :
- 1.Spring中一个类创建对象的过程,首先从 getSingleton 方法中查看Spring一级缓存 singletonObjects 中是否有该对象,通过该方法中的调用 isSingletonCurrentlyInCreation 方法判断该对象是否在创建中,什么叫做创建中?即已经实例化了对象,但是还没有给都对象进行属性赋值。如果在创建中,则查看二级缓存中是否有该对象,如果没有接着查看三级缓存。
-
- 实例化对象之后,在进行属性赋值之前,即调用 populateBean 之前,会调用 addSingletonFactory 方法将对象实例放入到Spring三级缓存 singletonFactories 中,然后后面进行属性赋值以及初始化,
-
- 对象实例化,属性赋值以及初始化完成之后调用 addSingleton 方法将该对象放入到一级缓存 singletonObjects 中。
循环依赖的详细步骤如下:
首先进行A实例化,接着将A对象放入到三级缓存 singletonFactories 中,然后调用 populateBean 进行属性赋值,发现需要依赖B对象,于是进行B对象的创建,首先 getSingleton 方法查看缓存中是否存在该对象,不存在则进行创建,实例化B对象之后,调用 populateBean 进行属性赋值,发现依赖A对象,于是进行A对象的创建,调用 getSingleton 方法查询一级缓存中没有该对象,但是A对象之前已经实例化过,但是还没有进行属性赋值,即属于创建过程中,于是查询二级和三级缓存中是否有该对象,当然该对象在三级缓存中,于是得到该对象,将该对象从三级缓存中移到二级缓存中;接着回来进行B对象中A属性的赋值,赋值完成之后,进行B对象的初始化,然后调用 addSingleton 方法将该对象放入到一级缓存s ingletonObjects 中;接着回来进行A对象中B属性的赋值操作,接着进行A对象的初始化,初始化话完成之后调用 addSingleton 方法将该对象放入到一级缓存 singletonObjects 中。
涉及的主要方法如下图所示
源码分析
/**
* 该方法完成IOC容器创建以及初始化工作
* 该方法中最重要的是第二步和第十一步
*
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// STEP 1: 刷新预处理
//准备工作包括设置启动时间,是否激活标识位,初始化属性源(property,source)配置
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//用DefaultListableBeanFactory的子类得到的是DefaultListableBeanFactory
//可以理解为初始化bean工厂
// STEP 2:
// a) 创建IoC容器(DefaultListableBeanFactory)
// b) 加载解析XML文件(最终存储到Document对象中)
// c) 读取Document对象,并完成BeanDefinition的加载和注册工作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//最重要的方法,准备bean工厂
// STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//这个方法在当前版本的spring是没有任何代码的,可能spring期待在后面的版本中进行扩展
//空壳方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//比较重要的方法
//在spring的环境中去执行已经被注册的factory processors
//设置执行自定义的ProcessorFactory和spring内部自己定义的(ConfigutationClassPoetProcessor)
//ConfigurationClassPostProcessor就是spring内部自己维护的BeanFactoryPostProcessor
//下面的方法主要执行ConfigurationClassPostProcessor中的方法
// STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
/**
* BeanFactoryPostProcessor是spring的扩展点之一
* 实现该接口,可以在spring的bean创建之前修改bean的定义属性
* spring允许BeanFactoryPostProcessor在容器实例化任何其他bean之前读取它配置的元数据
* 并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改
* 可以同时配置多个BeanFactoryPostProcessor,并且通过设置'order'属性来控制各个BeanFactoryPostProcessor
* BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的
* 可以写一个例子来测试以下这个功能
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//上一行的代码已经将一些后置处理器放到bdMap中了,包括自定义的BeanPostProcessor
// 注册BeanPostProcessor,即后置处理器,一共是7个
//把bdMap中的所有后置处理器拿出来,
// 再直接new另外一些后置处理器,一起放到工厂的list中
// STEP 6: 注册BeanPostProcessor后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//不重要,国际化的处理
// STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
initMessageSource();
// Initialize event multicaster for this context.
//事件处理,用的比较少,不重要
// STEP 8: 初始化应用事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//这是一个空壳方法,里面没有代码
// STEP 9: 初始化一些特殊的bean
onRefresh();
// Check for listener beans and register them.
//对一些监听器的注册,先放一放
// STEP 10: 注册一些监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//重点,重点
//完成bean的实例化
// STEP 11: 实例化剩余的单例bean(非懒加载方式)
// 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// STEP 12: 完成刷新时,需要发布对应的事件
finishRefresh();
}
}
查看第十一步:finishBeanFactoryInitialization(beanFactory)方法
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//省去不重要代码
// Instantiate all remaining (non-lazy-init) singletons.
//最重要的代码
//这里调用的DefaultListableBeanFactory中的preInstantiateSingletons
//实例化所有的单例对象
beanFactory.preInstantiateSingletons();
}
//真正调用这里,重点
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//从bdMap拿到所有需要初始化的类
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//这行代码不重要,合并父类的bd,这种应用很少用
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//肯定会进到if中
//如果bean不是抽象的,而且是单例的,同时还不是懒加载的,则进行下面的操作
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//这里判断是不是FactoryBean
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
//重点
getBean(beanName);
}
}
}
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//因为你的beanName有可能加了&,所以要将&移除
//这里用到的是FactoryBean的知识
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//从三级缓存中获取bean对象,面试重点 spring三级缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//重点,容器中没有该对象的实例
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 如果是原型,不应该在初始化的时候创建
* spring当中的标识CurrentlyInCreation标识该类正在创建
* spring容器循环依赖报错演示BeanCurrentlylnCreationException
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
try {
// Create bean instance.
//重点重点
if (mbd.isSingleton()) {
/**
* getSingleton相当于从缓存中根据beanName取出对象,
* 如果取不到,就回调下面的匿名内部类的createBean方法
*/
sharedInstance = getSingleton(beanName, () -> {
try {
//重点
//真正调用AbstractAutowireCapableBeanFactory中的createBean方法
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;
}
transformedBeanName
将 name 转换为真正的 beanName(name 可能是 FactoryBean 以 & 字符开头或者有别名的情况,所以需要转化下)
/**
* 从三个map中拿出单例bean
* 三个缓存
*
* 三级缓存问题 循环依赖问题
* 三级缓存就是为了解决循环依赖
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//这个singletonObjects就是微观springioc容器
//从一级缓存中获取单例对象
Object singletonObject = this.singletonObjects.get(beanName);
/**
* isSingletonCurrentlyInCreation
* 判断当前单理bean是否正在创建中,也就是已经创建了对象实例但是还没有完成属性赋值
* 比如A的构造器依赖了B对象所以得先去创建B对象,或者A的populateBean过程中依赖了B对象,得先去创建B对象
* 这是A就是处于创建中的状态
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存中获取单例bean
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference是否允许从singletonFactories中通过getObject查到对象
if (singletonObject == null && allowEarlyReference) {
//从三级缓存中获取单理bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//从三级缓存移动代理二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 然后第一个通过
getSingleton(beanName)
方法尝试从一级缓存singletonObjects中查找是不是有该实例 sharedInstance,如果没有则调用isSingletonCurrentlyInCreation(beanName)
判断该对象是否在创建中,何为创建中?简单的理解就是对象已经实例化,但是还没有填充属性和初始化(单例在 Spring 的同一容器只会被创建一次,后续再获取 bean,就直接从缓存获取即可)isSingletonCurrentlyInCreation(beanName)
方法代码如下:
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
回到上面的 getSingleton(beanName)
方法,如果该对象正在创建中,则尝试从二级缓存earlySingletonObjects
中获取,如果二级缓存中还获取不到,则尝试从三级缓存singletonFactory
中获取。beanName为a的一开始进来getSingleton(beanName)
时,三个缓存中都没有包含beanName为a的,所以此时返回为null.
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//因为你的beanName有可能加了&,所以要将&移除
//这里用到的是FactoryBean的知识
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//从三级缓存中获取bean对象,面试重点 spring三级缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//重点,容器中没有该对象的实例
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 如果是原型,不应该在初始化的时候创建
* spring当中的标识CurrentlyInCreation标识该类正在创建
* spring容器循环依赖报错演示BeanCurrentlylnCreationException
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
try {
// Create bean instance.
//重点重点
if (mbd.isSingleton()) {
/**
* getSingleton相当于从缓存中根据beanName取出对象,
* 如果取不到,就回调下面的匿名内部类的createBean方法
*/
sharedInstance = getSingleton(beanName, () -> {
try {
//重点
//真正调用AbstractAutowireCapableBeanFactory中的createBean方法
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;
}
接着我们继续看第二个包含lamda表达式的getSingleton
方法,如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//尝试从一级缓存中获取bean,此时为null
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//往上面说的存储正在创建中对象的容器singletonsCurrentlyInCreation中添加该beanName
beforeSingletonCreation(beanName);
try {
//这行代码是真正创建对象的,该对象已经是一个代理对象了,重点
/**
* 后置处理器就是再这里把原生的变成代理对象,去看匿名内部类中的createBean方法
* 这里其实就是调用外面的lamda表达式中的createBean方法
*/
singletonObject = singletonFactory.getObject();
//调用lamda表达式createBean方法创建完对象之后,将该变量置为true
newSingleton = true;
}
catch (IllegalStateException ex) {
}
if (newSingleton) {
//重点,三级缓存解决循环依赖问题
//实例化完成对象,并且对象设只属性和完成初始化之后
//及那个该对象放入到一级缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
这个getSingleton
方法主要的逻辑:首先从一级缓存singletonObjects
中获取,此时获取不到为null
,接着将当前的beanName为a的存入到上面提到的存储存储正在创建中对象的singletonsCurrentlyInCreation
中,然后调用singletonFactory.getObject();
,本质就是调用外面的lamda表达式中createBean方法创建beanName为a的对象,调用完createBean
方法创建对象之后,接着将标识newSingleton
置为true,然后调用addSingleton
方法将创建出来的对象加入到一级缓存singletonObjects
中。
addSingleton
方法如下:将创建出来的完整对象(即已经实例化,填充属性以及初始化之后的对象)加入到一级缓存singletonObjects中,然后将二级缓存和三级缓存中删除掉。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//将对象放入到一级缓存中
this.singletonObjects.put(beanName, singletonObject);
//从三级缓存中移除对象
this.singletonFactories.remove(beanName);
//从二级缓存中移除对象
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
接着查看createBean
方法创建对象,如下:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//将不重要的代码省略
try {
//真正实例化bean(还有填充属性,初始化)的方法在这一行
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
接着查看doCreateBean
方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//BeanWrapper把真实对象包装了一层,该类中的getWrappedInstance返回真实对象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//开始创建真实对象的包装类,利用反射
//默认调用无参构造实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//这里从包装类中拿出的是原生对象,而不是代理对象,接着下面的操作把原生对象变成代理对象
final Object bean = instanceWrapper.getWrappedInstance();
}
// 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));
//如果要提前暴露单理bean,则将该bean加入到三级缓存中
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//重要,一定要进去看看
//把创建出来的对象放入相应的map中
//将刚创建的bean放入到三级缓存中 singleFactories(key是besnName,value是FactoryBean)
//singletonFactory是通过lamda表达式获取得到的
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//赋值属性的,重要
//主要借助Common和Autowired两个后置处理器来填充属性
//bean初始化第二步:填充属性(DI依赖注入发生在此步骤)
populateBean(beanName, mbd, instanceWrapper);
/**
* 重点,这里就是把原生对象变成代理对象的地方
* bean初始化第三步:调用初始化方法,完成bean的初始化,aop发生在此步骤
* 例如<besn init-method=""></besn>中的init-method方法就是在这里调用的
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
return exposedObject;
}
上述代码中,首先调用createBeanInstance(beanName, mbd, args);
底层通过反射创建出a对象,接着调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
将创建出来的对象a加入到三级缓存singletonFactories
中,addSingletonFactory
方法如下:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
//首先判断一级缓存中是否有对象
if (!this.singletonObjects.containsKey(beanName)) {
//首先将关键字为beanName,value为lamda表达式中获取出来的singletonFactory
//放到三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
注意,() -> getEarlyBeanReference(beanName, mbd, bean)
中的getEarlyBeanReference
方法如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//提供扩展用的,也就是允许将对象存入三级缓存之前做其他的事情
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
将对象a加入到三级缓存singletonFactory
之后,接着对象a调用populateBean(beanName, mbd, instanceWrapper);
进行填充属性,如下;
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//省略无关代码
//获取出所有的property属性值,因为在组装BeanDefinition对象时,将类的属性放入到了PropertyValues中
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (pvs != null) {
//基于xml方式
//完成依赖注入
//PropertyValues pvs:待依赖的属性值集合
//BeanWrapper bw:实例化后的Bean的包装对象
//xml方式的属性注入在这里
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
接着查看applyPropertyValues
方法如下:
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//遍历所有A类中属性,依赖的B类属性就在其中
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
//循环依赖重点,由于依赖B类,所有需要将B类对象先创建出来resolvedValue
//!!!!重点
//一位属性中的对象还没有创建,所以不能直接设置属性值,必须先创建属性对象
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// Set our (possibly massaged) deep copy.
try {
//将创建出来的B类对象填充到A对象中
//完成依赖注入
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
}
}
上述代码中,首先调用valueResolver.resolveValueIfNecessary
处理a对象依赖B类的问题,将会创建出B类对象,接着最后调用bw.setPropertyValues
将B类对象作为属性填充到A对象中。
咱们接着看resolveValueIfNecessary
方法创建B类对象的过程,如下:
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//重点看该方法
return resolveReference(argName, ref);
}
//省略无关代码
}
接着查看resolveReference
方法,如下:
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
//重点!!!
//从Spring容器中找属性对象
//进去之后发现跟刚刚创建对象是一样的过程
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
return bean;
}
catch (BeansException ex) {
}
}
上述代码中,调用this.beanFactory.getBean(refName);
创建出B类对象,创建对象流程跟创建A类对象类似,接着查看getBean
方法,如下:
doGetBean
=> createBean
=> doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
if (instanceWrapper == null) {
//开始创建真实对象的包装类,利用反射
//默认调用无参构造实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//这里从包装类中拿出的是原生对象,而不是代理对象,接着下面的操作把原生对象变成代理对象
final Object bean = instanceWrapper.getWrappedInstance();
/**
* 解决循环依赖的关键步骤
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
//如果要提前暴露单理bean,则将该bean加入到三级缓存中
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//重要,一定要进去看看
//把创建出来的对象放入相应的map中
//将刚创建的bean放入到三级缓存中 singleFactories(key是besnName,value是FactoryBean)
//singletonFactory是通过lamda表达式获取得到的
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//赋值属性的,重要
//主要借助Common和Autowired两个后置处理器来填充属性
//bean初始化第二步:填充属性(DI依赖注入发生在此步骤)
populateBean(beanName, mbd, instanceWrapper);
/**
* 重点,这里就是把原生对象变成代理对象的地方
* bean初始化第三步:调用初始化方法,完成bean的初始化,aop发生在此步骤
* 例如<besn init-method=""></besn>中的init-method方法就是在这里调用的
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
return exposedObject;
}
当创建完B类对象,也将B类对象存入到三级缓存singletonFactories
中,填充B类对象属性时,发现依赖A类,接着同理调用populateBean
=> applyPropertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//遍历所有的属性进行填充,包括A类对象
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
//循环依赖重点
//!!!!重点
//一位属性中的对象还没有创建,所以不能直接设置属性值,必须先创建属性对象
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// Set our (possibly massaged) deep copy.
try {
//重点
//完成依赖注入
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
}
同理,通过resolveValueIfNecessary
查找A类对象,最后通过setPropertyValues
将A类对象填充到B类对象属性中,查看resolveValueIfNecessary
,如下:
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//重点看该方法
return resolveReference(argName, ref);
}
}
同理查看resolveValueIfNecessary
方法,如下:
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
if (ref.isToParent()) {
}
else {
//重点!!!
//从Spring容器中找属性对象
//进去之后发现跟刚刚创建对象是一样的过程
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
}
接着getBean
方法走上面同样的流程获取对象a,getBean
=> doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//因为你的beanName有可能加了&,所以要将&移除
//这里用到的是FactoryBean的知识
final String beanName = transformedBeanName(name);
Object bean;
//从三级缓存中获取bean对象,面试重点 spring三级缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//重点,容器中没有该对象的实例
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 如果是原型,不应该在初始化的时候创建
* spring当中的标识CurrentlyInCreation标识该类正在创建
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Create bean instance.
//重点重点
if (mbd.isSingleton()) {
/**
* getSingleton相当于从缓存中根据beanName取出对象,
* 如果取不到,就回调下面的匿名内部类的createBean方法
*/
sharedInstance = getSingleton(beanName, () -> {
try {
//重点
//真正调用AbstractAutowireCapableBeanFactory中的createBean方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
catch (BeansException ex) {
}
}
return (T) bean;
}
注意此时a对象已创建出来并存入到三级缓存中了,查看Object sharedInstance = getSingleton(beanName);
,如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//这个singletonObjects就是微观springioc容器
//从一级缓存中获取单例对象
Object singletonObject = this.singletonObjects.get(beanName);
/**
* isSingletonCurrentlyInCreation
* 判断当前单理bean是否正在创建中,也就是已经创建了对象实例但是还没有完成属性赋值
* 比如A的构造器依赖了B对象所以得先去创建B对象,或者A的populateBean过程中依赖了B对象,得先去创建B对象
* 这是A就是处于创建中的状态
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存中获取单例bean
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference是否允许从singletonFactories中通过getObject查到对象
if (singletonObject == null && allowEarlyReference) {
//从三级缓存中获取单理bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//从三级缓存移动代理二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
此时会将a对象从三级缓存singletonFactory
移到二级缓存earlySingletonObjects
中,并返回a对象。回到上面B类对象填充属性那一步,填充完a对象属性之后,接着初始化完成对象的完整操作,回到创建b对象doGetBean
那一步,继续查看
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//因为你的beanName有可能加了&,所以要将&移除
//这里用到的是FactoryBean的知识
final String beanName = transformedBeanName(name);
Object bean;
//从三级缓存中获取bean对象,面试重点 spring三级缓存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
}
//如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//重点,容器中没有该对象的实例
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
* 如果是原型,不应该在初始化的时候创建
* spring当中的标识CurrentlyInCreation标识该类正在创建
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Create bean instance.
//重点重点
if (mbd.isSingleton()) {
/**
* getSingleton相当于从缓存中根据beanName取出对象,
* 如果取不到,就回调下面的匿名内部类的createBean方法
*/
sharedInstance = getSingleton(beanName, () -> {
try {
//重点
//真正调用AbstractAutowireCapableBeanFactory中的createBean方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
return (T) bean;
}
查看第二个带lamda表达式的getSingleton
方法如下:此时已经执行完lamda比表达式createBean
方法,即下面的singletonObject = singletonFactory.getObject();
这一行代码,最终执行addSingleton
将对象b加入到一级缓存singletonObjects中。
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) {
//往正在创建的bean的标识的容器中添加该beanName
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//这行代码是真正创建对象的,该对象已经是一个代理对象了,重点
/**
* 后置处理器就是再这里把原生的变成代理对象,去看匿名内部类中的createBean方法
* 这里其实就是调用外面的lamda表达式中的createBean方法
*/
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
}
if (newSingleton) {
//重点,三级缓存解决循环依赖问题
//实例化完成对象,并且对象设只属性和完成初始化之后
//及那个该对象放入到一级缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
B类对象创建完成,并且加入到一级缓存singletonObjects中,最终返回到A对象填充属性那一步,填充完属性之后,接着同理初始化,走完创建对象流程,也即doGetBean
那一步,接着同理,也回到上面的singletonObject = singletonFactory.getObject();
这一步,最后执行addSingleton
将对象a加入到一级缓存中。
总结
Spring解决循环依赖依靠的是Bean的“中间态"这个概念,而这个中间态指的是已经实例化但还没初始化的状态……>半成品。实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决。
Spring为了解决单例的循环依赖问题,使用了三级缓存
- 其中一级缓存为单例池〈 singletonObjects)
- 二级缓存为提前曝光对象( earlySingletonObjects)
- 三级缓存为提前曝光对象工厂( singletonFactories)。
假设A、B循环引用,实例化A的时候就将其放入三级缓存中,接着填充属性的时候,发现依赖了B,同样的流程也是实例化后放入三级缓存,接着去填充属性时又发现自己依赖A,这时候从缓存中查找到早期暴露的A,没有AOP代理的话,直接将A的原始对象注入B,完成B的初始化后,进行属性填充和初始化,这时候B完成后,就去完成剩下的A的步骤,如果有AOP代理,就进行AOP处理获取代理后的对象A,注入B,走剩下的流程。
总体步骤:
- 1 调用doGetBean()方法,想要获取beanA,于是调用getSingleton()方法从缓存中查找beanA
- 2 在getSingleton()方法中,从一级缓存中查找,没有,返回null
- 3 doGetBean()方法中获取到的beanA为null,于是走对应的处理逻辑,调用getSingleton()的重载方法(参数为ObjectFactory的)
- 4 在getSingleton()方法中,先将beanA_name添加到一个集合中,用于标记该bean正在创建中。然后回调匿名内部类的creatBean方法
- 5 进入AbstractAutowireCapableBeanFactory#doCreateBean,先反射调用构造器创建出beanA的实例,然后判断。是否为单例、是否允许提前暴露引用(对于单例一般为true)、是否正在创建中〈即是否在第四步的集合中)。判断为true则将beanA添加到【三级缓存】中
- 6 对beanA进行属性填充,此时检测到beanA依赖于beanB,于是开始查找beanB
- 7 调用doGetBean()方法,和上面beanA的过程一样,到缓存中查找beanB,没有则创建,然后给beanB填充属性
- 8 此时beanB依赖于beanA,调用getsingleton()获取beanA,依次从一级、二级、三级缓存中找,此时从三级缓存中获取到beanA的创建工厂,通过创建工厂获取到singletonObject,此时这个singletonObject指向的就是上面在doCreateBean()方法中实例化的beanA
- 9 这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中
- 10 随后beanA继续他的属性填充工作,此时也获取到了beanB,beanA也随之完成了创建,回到getsingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中