文章目录
- 概要
- 主流程
- bean的创建
- 循环依赖
概要
容器初始化时,会创建单例bean,本文主要关注单例bean是如何创建的,并说明源码中是如何解决循环依赖的
代码入口
@Testpublic void testIoC() {// ApplicationContext是容器的高级接口,BeanFactory(顶级容器/根容器,规范了/定义了容器的基础行为)// Spring应用上下文,官方称之为 IoC容器(错误的认识:容器就是map而已;准确来说,map是ioc容器的一个成员,// 叫做单例池, singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)/*** Ioc容器创建管理Bean对象的,Spring Bean是有生命周期的* 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization* Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors* Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors*/// ClassPathXmlApplicationContext-> AbstractXmlApplicationContext// -> AbstractRefreshableConfigApplicationContext ->AbstractRefreshableApplicationContextApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");NormalBean normalBean = applicationContext.getBean(NormalBean.class);System.out.println(normalBean);}
以下是spring源码启动的主流程入口
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");/*** 刷新前的预处理* 表示在真正做refresh操作之前需要准备做的事情* 设置spring容器的启动时间* 开启活跃状态,撤销关闭状态* 验证环境信息里一些必须存在的属性等*/prepareRefresh();/*** 获取BeanFactory;默认实现是DefaultListableBeanFactory* 加载BeanDefition 并注册到 BeanDefitionRegistry*/ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();/*** 第三步: BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加* 载器等)*/prepareBeanFactory(beanFactory);try {// 第四步: BeanFactory准备⼯作完成后进⾏的后置处理⼯作postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);initMessageSource();// Initialize event multicaster for this context.// 第⼋步:初始化事件派发器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑onRefresh();// Check for listener beans and register them.// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器beanregisterListeners();// Instantiate all remaining (non-lazy-init) singletons./*第⼗⼀步:初始化所有剩下的⾮懒加载的单例bean初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)填充属性初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、 init-method⽅法)调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处*/finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event./*第⼗⼆步:完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)*/finishRefresh();} catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;} finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}
主流程
关于bean的三级缓存,DefaultSingletonBeanRegistry
中的变量,如下
/**
* 一级缓存:单例(对象)池,这里面的对象都是确保初始化完成,可以被正常使用的
* 它可能来自3级,或者2级
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 三级缓存:单例工厂池,这里面不是bean本身,是它的一个工厂,未来调getObject来获取真正的bean
* 一旦获取,就从这里删掉,进入2级(发生闭环的话)或1级(没有闭环)
*/
private final Map<String, ObjectFactory<?>> singletonFactories = newHashMap<>(16);
/**
* 二级缓存:早期(对象)单例池,这里面都是半成品,只是有人用它提前从3级get出来,把引用
暴露出去
* 它里面的属性可能是null,所以叫早期对象,early!半成品
* 未来在getBean付完属性后,会调addSingleton清掉2级,正式进入1级
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
关于单例bean的生命周期,其主要包括以下几个方面
各个部分的细节如下:
bean的创建
代码层面,主要关注以下几个方法
入口:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("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.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 是否抽象 是否单例 是否延迟创建if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {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 {// 不是工厂bean,普通bean的创建getBean(beanName);}}}....
}
@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// 判断一级缓存中是否存在Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 二级缓存中是否存在singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 再从三级缓存中获取ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
注意这里有个细节,先判断二级中缓存是否存在,不存在再从三级缓存中获取。这里很重要,也是为什么要有二级缓存存在的原因。
触发函数式接口
下面看:AbstractAutowireCapableBeanFactory#createBean(String,RootBeanDefinition,Object[])
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 调用构造函数创建bean 未设置属性instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}synchronized (mbd.postProcessingLock) {...}// 是否单例 是否允许循环引用 是否 正在创建->提前暴露boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {...// 放入到三级缓存中addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// bean属性填充populateBean(beanName, mbd, instanceWrapper);// 调用初始化方法,应用BeanPostProcessor方法exposedObject = initializeBean(beanName, exposedObject, mbd);} catch (Throwable ex) {..}...return exposedObject;}
到这里,初始化bean的主流程就跑完了,在没有循环依赖的情况下,bean的正常创建就是经历了以上主流程代码。下面仔细分析下org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);}}return exposedObject;}
bean在用构造函数创建后,此时还没有设置属性值,会提前把一个函数式接口放入到三级缓存中,上面的getEarlyBeanReference
方法,就是在addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
放入到三级缓存中。进入到里面可以看到跟创建代理对象有关。所以此处将接口放入到三级缓存主要有以下两个作用:
- 提前暴露正在创建的对象,如果有其他对象引用了该对象,那么就可以直接从三级缓存中获取
- 如果该对象需要被增强,要被创建代理对象,那么该函数式接口也能保证,其他对象依赖的是增强后的对象
循环依赖
下面从源码分析,spring是如何解决循环依赖的。
循环依赖涉及到三级缓存的的变化,下面围绕三级缓存的变化梳理主要流程
有配置文件如下
<!--循环依赖BeanA依赖BeanB -->
<bean id="userServiceImplA" class="com.spring.test.impl.UserServiceImplA">
<property name="userServiceImplB" ref="userServiceImplB"/>
</bean>
<!--循环依赖BeanB依赖BeanA -->
<bean id="userServiceImplB" class="com.spring.test.impl.UserServiceImplB">
<property name="userServiceImplA" ref="userServiceImplA"/>
</bean>
上面看出对象A引用了对象B,同时对象B也引用了对象A,对象A、B之间存在循环依赖
对象B在设置属性值A时,会调getBean方法,从容器中获取对象,从而会重新走一遍上面的主流程,入口如下
org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference
在走一遍主流程时,在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
方法中,会发现三级缓存中已经存在对象A了,就直接从三级缓存中获取
这里要注意的时,三级中A的会被移除,从而转移到二级缓存中,这里为什么要从三级缓存中移除呢?假如有个对象C也引用了A,并且对象A是需要创建动态代理的,如果不从3级缓存中进行移除,那么A对象就会被重复执行到三级缓存中的函数式接口,这样就是产生多个A的代理对象。从三级缓存中移除,并转移到二级缓存中,这样,当C也需要A时,直接从二级缓存中进行获取就可以了,就不会造成创建多个A对象的代理对象。