概要
容器初始化时,会创建单例bean,本文主要关注单例bean是如何创建的,并说明源码中是如何解决循环依赖的
代码入口
@Test
public 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 ->AbstractRefreshableApplicationContext
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
NormalBean normalBean = applicationContext.getBean(NormalBean.class);
System.out.println(normalBean);
}
以下是spring源码启动的主流程入口
@Override
public 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接⼝的监听器bean
registerListeners();
// 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);
}
}
}
....
}
@Nullable
protected 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对象的代理对象。