Spring源码系列:bean生命周期及循环依赖

13 篇文章 2 订阅
11 篇文章 0 订阅

1、Spring中bean的创建流程

bean创建的简易流程如下所示:

  1. 首先调用createBeanInstance方法进行bean的实例化
  2. 然后调用populateBean进行属性的填充
  3. 接着调用initializeBean进行后置处理
  4. 最后调用getSingleton方法添加到单例池中

以上createBeanInstance、populateBean和initializeBean均属于类org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory,getSingleton方法属于org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

接下来就看看详细的流程

2、Spring创建bean的详细流程

首先我么来看看使用AnnotationConfigApplicationContext这个配置类加载bean的时候,创建一个bean会走哪些流程:

image-20210408150731343

从上图中,我们可以知道创建bean最终会调用doCreateBean方法,这个doCreateBean最终完成了创建bean实例、进行属性填充和后置处理的功能!

image-20210408151853505

首先需要知道一点,也就是ApplicationContext中的beanFactory一般是DefaultListableBeanFactory,这点我们从上图中可以得知,所以我们直接通过这个类来探索Spring中加载bean的过程。

2.1 调试程序

首先,来看一段程序用来协助我们查看bean的创建流程:

	public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(AService.class);
        rootBeanDefinition.setPropertyValues(new MutablePropertyValues().add("id", "88888888"));
        beanFactory.registerBeanDefinition("service", rootBeanDefinition);
        
		/*
		可以在此处打断点进行调试,从而获取bean的创建流程,到此流程时直接进入即可
		*/
        beanFactory.getBean("service");
    }
	public static class AService {
        private String id;

        public void setId(String id) {
            this.id = id;
        }
    }

通过调试我们可以知道,调用getBean方法会首先调用DefaultListableBeanFactory父类AbstractBeanFactory的doGetBean方法,这点从调试的方法调用信息就可以看到:

image-20210407155632259

在调用doGetBean的方法中,会进行两次调用getSingleton,这两次调用第一次是用于获取bean,由于此时还不存在这个bean,所以在第二次调用时就用于创建这个bean,接下来看看这两次调用:

2.2 doGetBean

第一次调用:

第一次调用

这次调用只向getSingleton中传入了beanName,此时bean对象还未创建,无法获取到bean对象,并且bean对象并未处于正在创建的单例集合中,所以会直接返回null,此时调用的是getSingleton(String beanName, boolean allowEarlyReference)方法

第二次调用:

第二次调用的方法为getSingleton(String beanName, ObjectFactory<?> singletonFactory),这里使用了lambda表达式传入了ObjectFactory对象,为什么是ObjectFactory对象呢,这点可以通过调试的方式看出来,当执行到这个方法以后,会调用getSingleton的另一个重载方法,这个重载方法里面的参数就是ObjectFactory,也可以接着运行看下去。

image-20210407160203661

2.3 getSingleton方法

接下来我们看看getSingleton方法的实现,这里调用的是org.springframework.beans.factory.support.DefaultSingletonBeanRegistry的getSingleton方法:

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
        // 从singletonObjects中获取beanName对应的bean实例化对象,singletonObjects翻译过来就是单例池
		Object singletonObject = this.singletonObjects.get(beanName);
        // 如果单例池中不存在该对象,并且该对象为正在创建中的单例对象,那么就进入循环
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 从earlySingletonObjects中获取beanName对应的对象
			singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果获取到的对象仍然为空的话,并且允许暴露早期的引用,那么就会进入该循环
			if (singletonObject == null && allowEarlyReference) {
                // 此时会锁住singletonObjects这个属性
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
                    // 继续从singletonObjects中获取该对象
					singletonObject = this.singletonObjects.get(beanName);
                    // 判断对象是否被成功创建出来,如果创建出来就不再创建,直接返回,防止该对象重新创建,这里类似于单例模式的双重校验锁
					if (singletonObject == null) {
                        // 当这个单例对象确实没有创建出来时,那么我们就继续看earlySingletonObjects是否包含该对象
						singletonObject = this.earlySingletonObjects.get(beanName);
                        // 继续判断这个对象有没有被创建出来,也是为了避免重复创建
						if (singletonObject == null) {
                            // 如果singletonObjects和earlySingletonObjects中都没有这个对象,那就从singletonFactories中获取到这个对象的工厂
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            // 如果这个对象工厂不为空就继续进入下面的流程
							if (singletonFactory != null) {
                                // 调用singletonFactory.getObject()方法获取到这个对象
								singletonObject = singletonFactory.getObject();
                                // 将这个对象加入到earlySingletonObjects中去
								this.earlySingletonObjects.put(beanName, singletonObject);
                                // 从singletonFactories中移除这个对象,有助于垃圾回收
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
        // 最后返回这个对象
		return singletonObject;
	}

getSingleton的重载方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
    	// 首先锁住singletonObjects对象
		synchronized (this.singletonObjects) {
            // 从单例池中获取beanName对应的bean对象
			Object singletonObject = this.singletonObjects.get(beanName);
            // 如果单例池中不存在该对象,就继续下面的流程
			if (singletonObject == null) {
                // 如果当前正处于对象的销毁状态则不允许新建对象,并抛出异常
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
                // 将对象加入正在创建的集合
				beforeSingletonCreation(beanName);
                // 标识这个对象是否为新创建的对象
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
                    // 从singletonFactory中生产对象,调用传递进来的lambda里面的方法中生产对象
					singletonObject = singletonFactory.getObject();
                    // 证明此对象为新创建的对象
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
                    // 从正在创建的对象集合中删除该对象
					afterSingletonCreation(beanName);
				}
                // 如果该对象为新创建成功的对象,那么将这个兑现加入到单例池中
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
            // 返回这个新创建的对象
			return singletonObject;
		}
	}
/**
* 判断对象是否正在创建,如果是的话将其加入正在创建的集合,否则抛出异常
*/
protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
/**
* 将bean对象从正在创建的集合中删除
*/
protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

2.4 createBean方法

当我们继续执行getSingleton方法时,其中的singletonFactory.getObject()方法会进入到这个lambda表达式中,调用其中的方法,也就是createBean方法。

image-20210407163348891

我们来看看createBean方法,该方法会调用doCreateBean方法,createBean方法会对传入的RootBeanDefinition做一系列的设置以及初始化操作,然后再传递给doCreateBean方法

image-20210407164035522image-20210407163950554

2.5 doCreateBean方法

在doCreateBean方法中会调用createBeanInstance方法,在该方法中使用适当的实例化策略为指定bean创建一个新实例:工厂方法、构造函数自动连接或简单实例化。

image-20210407185843204

image-20210407185958010

这个方法里面会推断我们bean的构造函数,然后进行相应的实例化,注意此时还不算是bean对象。如果没有推断出来合适的构造函数,会调用无参构造函数将对象实例化,由于我们的对象就没有提供构造函数,所以只能使用无参构造函数初始化,此时会调用instantiateBean方法:

image-20210407164829269

继续进入到instantiateBean方法中去,这个方法的作用就是使用无参构造函数为我们实例化出来一个普通的对象,创建出来的实例化对象会被包装成一个BeanWrapper对象,最终会返回给doCreateBean方法,我们继续来看doCreateBean这个方法。回到这个方法后,我们可以运行可以看到下面这行代码,这行代码就是将singletonFactory加入到singletonFactories中去,然后在getSingleton方法中会调用这个对象的getObject方法制造相应的对象。

image-20210407165508536

接着我们继续向下看,下面就会遇到populateBean和initializeBean这两个方法了,这两个方法分别是给bean填充属性和对bean进行初始化操作的。在属性填充阶段可能会遇到循环依赖,有关循环依赖的问题后续再将。

image-20210407165942524

属性填充完成后会进行bean的初始化操作

image-20210407170428118

至此,doCreateBean方法算是完成了。接着会继续调用getSingleton方法,继续进行bean对象的创建工作。

当对象创建完成以后,会将这个新对象添加到单例池中,此时会调用addSingleton方法。

image-20210407170821400

2.6 addSingleton方法

addSingleton方法属于类DefaultSingletonBeanRegistry

protected void addSingleton(String beanName, Object singletonObject) {
    	// 锁住singletonObjects对象
		synchronized (this.singletonObjects) {
            // 将bean的名称及对应的实例加入到singletonObjects中去,以后获取对象也是从单例池中获取
			this.singletonObjects.put(beanName, singletonObject);
            // 将singletonFactories和earlySingletonObjects中对应名称的对象移除,帮助jvm垃圾回收
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
            // 在registeredSingletons添加已经完成实例化的bean的名称
            // registeredSingletons中记录了一系列的bean的名称
			this.registeredSingletons.add(beanName);
		}
	}

当这一系列方法调用完成以后,这个bean的创建流程就结束了。

这里只讨论了单例作用域的bean的创建过程,当bean为原型或者其他作用域时可以自己去尝试调试跟踪它们对应的流程。

2.7 回到doGetBean

最后我们又回到了doGetBean方法中,当我们获取完bean对象以后,还需要检查这个bean对象与给定的类型是否一致,如果不一致还需要进行一定的转换,如果一致的话则直接返回这个bean即可。

3、总结

方法调用流程图

image-20210407190720161

4、循环依赖的解决

通过上面了解了Spring中bean的加载机制,接下来了解spring是如何解决循环依赖的就好办了!

spring的循环依赖包括构造器循环依赖和setter方法循环依赖,spring只能解决setter方法的循环依赖,但是不能解决构造器的循环依赖;此外,spring只能解决bean的作用域为单例的循环依赖,不能解决prototype作用域及其他作用域的循环依赖,这几点要记住!

首先先看看什么是循环依赖:

image-20210407211247560

通过上图我们可以发现,AService中依赖b属性,而BService中依赖a属性,这就造成了循环依赖;实例化AService后注入属性时,注入b,此时就要实例化BService,对BService进行属性填充时,又要实例化a,这就是典型的循环依赖,看看这个循环依赖是怎么在代码中实现的:

public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(AService.class);
            // rootBeanDefinition.setScope("prototype");
            rootBeanDefinition.setPropertyValues(new MutablePropertyValues().add("b",
                    new RuntimeBeanReference("bService")));
            beanFactory.registerBeanDefinition("aService", rootBeanDefinition);
        }
        {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BService.class);
            rootBeanDefinition.setPropertyValues(new MutablePropertyValues().add("a",
                    new RuntimeBeanReference("aService")));
            beanFactory.registerBeanDefinition("bService", rootBeanDefinition);
        }
        Object service = beanFactory.getBean("aService");
        System.out.println(service);
    }

    public static class AService {
        private BService b;

        public BService getB() {
            return b;
        }

        public void setB(BService b) {
            this.b = b;
        }
    }
    public static class BService {
        private AService a;

        public AService getA() {
            return a;
        }

        public void setA(AService a) {
            this.a = a;
        }
    }

运行上面这段代码,我们发现可以正常输出结果,那么这就证明spring帮助我们解决了循环依赖,那究竟是怎么解决的呢,我们来一探究竟(此时我们上面介绍的bean的创建过程就派上了用场)。

我们再来看一个流程图:

image-20210407214602283

4.1 AService第一次创建流程

我们来看看当遇到循环依赖时是如何创建AService的:

  1. 首先通过getBean方法获取AService时,会调用AbstractBeanFactory中的doGetBean方法

    • 在doGetBean方法中,首先会调用一次getSingleton方法,此时只传bean的名称,然后根据bean的名称查询singletonObjects是否包含该beanName对应的bean实例,如果不存在,则去访问singletonFactories,看是否存在对应的ObjectFactory对象,如果还是不存在就退出,这里由于是第一次创建,所以不会存在的,所以到这里方法就退出了,返回了一个null
    • 接着就会进行一系列的属性设置和判断,然后会重新调用getSingleton方法,此时会调用另一个重载方法getSingleton(String beanName, ObjectFactory<?> singletonFactory),然后使用lambda表达式传入了ObjectFactory对象接着会在lambda表达式中调用createBean方法
  2. 调用createBean方法,设置了RootBeanDefinition的一些属性,然后会接着调用doCreateBean方法

  3. 在doCreateBean方法中:

    • 首先调用createBeanInstance方法创建bean的实例,此时会解析bean对应的构造函数,但是不会处理构造函数中的循环依赖,所以构造函数的循环依赖不能解决

    • 当创建完bean的实例后,会判断bean是否为单例的,是否允许处理循环依赖,是否是正在创建的bean对象,当这一系列判断都为true时,会将这个半成品的bean包装成ObjectFactory对象添加到singletonFactories中

      image-20210407220531749

    • 然后就会调用populateBean方法进行属性的填充

      当通过名称自动注入时:image-20210407220841631

      当通过类型自动注入时:

      image-20210407221738871

      image-20210407221809634

      image-20210407221836825

      image-20210407221907740

      此时无论通过名称还是通过类型进行自动注入,都回调用getBean方法,此时就是getBean(“b”),要进入创建bean的流程了

  4. 此时创建AService的流程到此暂停了,我们要去进行BService的创建流程了!

4.2 BService的创建流程

由于上面的AService创建依赖了BService,所以我们就来创建BService了。创建BService的流程的前三步和创建AService的流程一样,但是到第四步就有所不同了,所以,这里忽略了前三步的创建流程,直接到属性注入这一步:

  1. BService属性注入:BService属性注入a时,会调用getBean(“a”)的方法,此时还是会调用AbstractBeanFactory#getBean方法,然后调用其doGetBean方法。
    • 在doGetBean方法中,会调用getSingleton(String beanName, boolean allowEarlyReference)方法,获取AService的对象,此时AService还没有创建完,但是我们可以从singletonFactory中获取到对应的ObjectFactory对象,通过singletonFactory.getObject()方法,可以获取半成品的bean,将这个bean放入earlySingletonObjects中,并从singletonFactories移除这个beanName对应的ObjectFactory对象,此时就解决了循环依赖的问题
  2. BService属性注入完成以后,会调用initializeBean方法进行bean的前置、初始化、后置处理,处理完成后就可以返回这个bean了
  3. 这个bean返回后,又到了getSingleton方法中,这个方法会将新创建的BService加入到singletonObjects中,调用的是addSingleton方法,该方法会清空singletonFactories和earlySingletonObjects中关于该BService对象的那些工厂对象和半成品对象垃圾回收

至此,BService的创建流程就结束了。

4.3 AService第一次创建流程续

BService已经创建完了,所以我们在AService的属性注入中可以注入这个对象了,将这个对象注入完成以后,会经历initializeBean的方法,最终在getSingleton方法中调用addSingleton方法将AService对象也加入到singletonObjects中。

4.4 相关问题

为什么使用singletonObjects、earlySingletonObjects和singletonFactories这三个缓存来解决循环依赖的问题呢?

因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。

使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致了。

为什么getBean的时候才执行getObject方法?为什么添加工厂的时候不直接执行getObject方法,而是先放到singletonFactories缓存中,再在getSingleton中进行调用呢?

这主要是因为后置处理有时会依赖于某些参数(这些参数指的是,我们有时会在properties配置参数,进行后置处理时可能会依赖这些参数,根据这些参数的不同走不同的流程),此时我们先添加的singletonFactory,然后再进行的属性填充,如果在添加工厂的时候就getObject那么此时属性还未填充,还无法使用这些属性,所以此时需要添加工厂,然后属性填充完成以后再调用getObject方法时就可以使用这些属性了.

5、参考

bilibili-鲁班大叔

欢迎访问我的个人博客哦
风在哪个人博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值