本文描述的IOC基于注解的方式启动容器
本文主要讲解refresh方法以及bean的创建过程,关于refresh执行前对于配置资源的读取加载可以看上一篇👉简单记录之SpringIOC初始化过程(一)
先贴上refresh()方法的代码:
public void refresh() throws BeansException, IllegalStateException {
//给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
synchronized (this.startupShutdownMonitor) {
//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
prepareRefresh();
//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
//子类的refreshBeanFactory()方法启动,里面有抽象方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册一些容器中需要的系统Bean,例如classLoader,beanFactoryPostProcessor等
prepareBeanFactory(beanFactory);
try {
//允许容器的子类去注册 postProcessor
postProcessBeanFactory(beanFactory);
//激活在容器中注册为 bean的 BeanFactoryPostProcessors
//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor
//方法扫描应用中所有BeanDefinition并注册到容器之中
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截 Bean创建过程的BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
//初始化事件发布器
//可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
initApplicationEventMulticaster();
//预留给AbstractApplicationContext 的子类用于初始化其他特殊的bean,
//该方法需要在所有单例 bean初始化之前调用
//比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
onRefresh();
//注册监听器(检查监听器的bean并注册他们)
registerListeners();
// 实例化所有剩余的(非延迟初始化)单例。
//设置自定义的类型转化器ConversionService
//设置自定义AOP相关的类LoadTime WeaverAware,
//清除临时的 ClassLoader
//实例化所有的类(懒加载的类除外)
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件处理器,(默认使用 DefaultLifecycleProcessor),调用扩展了SmartLifecycle
//当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
//并发布容器刷新完毕事件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 {
//重置Spring内今天核中的共用的缓存,因为我们可能再也不需要单例 bean的元数据了
resetCommonCaches();
}
}
}
这篇文章主要理清bean的创建过程,对于关键的方法会作为标题,其他的方法就简单的说说它的功能。
invokeBeanFactoryPostProcessors(beanFactory)
:激活在容器中注册为 bean的 BeanFactoryPostProcessors(根据在register方法中注册的BeanFactoryPostProcessor的BeanDefinition去创建对应的bean实例)。这一步除了创建BeanFactoryPostProcessor,另一个重要的动作就是——扫描应用中所有BeanDefinition并注册到容器之中,供后续容器创建bean实例。
registerBeanPostProcessors(beanFactory)
:将应用中所有的bean级别的后置处理器即BeanPostProcessor(上一个方法是beanFactory级别的后置处理器),根据beanDefinition去创建对应的实例。
finishBeanFactoryInitialization
此方法的作用:完成此容器(上下文)的bean工厂的初始化,初始化所有剩余的单例bean(懒加载的bean除外),然后调用该方法中的beanFactory.preInstantiateSingletons(),实例化所有剩余的非懒加载的单例
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) {
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);
}
}
}
//....
贴了一部分代码,可以看到会先判断这个bean是不是工程bean,即FactoryBean,如果是的话,则在beanName前加一个转义符&
,然后进行调用getBean()
方法进行下一步的操作。
其实在这里就可以看出,通过FactoryBean的方法向容器添加Bean,会创建两个Bean,一个是FactoryBean,另一个是工厂bean中的Bean。而获取他们的方法:获取工厂bean需要加FactoryBean的名字前加&,如果不加,获取到的就是工厂bean中的Bean。
getBean —> doGetBean
根据Spring中的方法命名习惯,do开头的方法是真正做事儿的方法,从getBean调用doGetBean没有额外的逻辑处理,所以就放一起了。
贴上部分的doGetBean
方法👇
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//通过三种形式获取beanName
//一个是原始的beanName,一个是加了&的,一个是别名
final String beanName = transformedBeanName(name);
Object bean;
//尝试从单例缓存集合里获取 bean实例
Object sharedInstance = getSingleton(beanName);
//如果先前已经创建过单例 Bean的实例,并且调用的 getBean方法传入的参数为空
//则执行if里面的逻辑
//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//如果是普通 bean,直接返回,如果是BeanFactory,则返回他的 getObject对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//若scope为prototype或者单例模式但是缓存中还不存在bean
else {
//如果scope为prototype并且显示还在创建中,则基本是循环依赖的情况
//针对prototype的循环依赖,spring无解,直接抛出异常
//A--B--A
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//..............................
//不想篇幅过长,中间一部分代码删除了
//..............................
//如果bean是单例
if (mbd.isSingleton()) {
//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//显式从单例缓存中删除 bean 实例
//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//................
//................
从代码中可以看到:
- 首先,通过
getSingleton()
方法,尝试从缓存中获取bean,如果有就返回,为null的话就进入到else的逻辑中。getSingleton()也是个重要的方法 - 在判断这个要创建的bean是会先进行scope为prototype的循环依赖的判断
具体是如何判断的:首先要明确一点,这里处理的循环依赖,是多例情况下的处理方式——直接抛出异常,即不支持多例的循环依赖。
如何检查:一个ThreadLocal<Object>
类型的prototypesCurrentlyInCreation,查看具体操作threadLocal的方法,可以看到,里面存储着正在创建的bean的名字的Set集合
。假设A,B相互依赖,创建A的时候,A被加入到Set中,当执行到A的成员变量的依赖注入的时候,也是执行getBean这个方法,所以,也会执行到doGetBean方法,当对B的成员变量进行注入的时候,又回去通过getBean去获取A,那么这时候Set已经存在A,所以就会抛出异常。
- 接下来就是判断beanDefinition的类型,单例还是多例,然后去执行createBean()方法
createBean
贴上部分代码👇
try {
//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建 Bean的代理对象
//resolveBeforeInstantiation只是针对有自定义的targetsource,
//因为自定义的targetsource不是spring的bean那么肯定不需要进行后续的一系列的实例化初始化。
//所以可以在resolveBeforelnstantiation直接进行 proxy
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//(创建bean的入口)
//如果在resolveBeforeInstantiation没有代理对象,则通过spring创建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
从代码中可以看到,在doCreateBean之前,会执行一个关键的方法——resolveBeforeInstantiation()
,跟进源码中可以看到,会去判断,容器中是否存在InstantiationAwareBeanPostProcessor
这样的bean级别的后置处理器,若有,则执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()
方法,如果在后置处理器中创建了bean,那么直接返回,等同于在spring创建bean的过程中用户做了截胡。如果没有,那么就执行doCreateBean()方法
doCreateBean
//bean实例包装类
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建bean的时候,这里创建bean的实例有三种方法
//1.工厂方法创建
//2.构造方法的方式注入
//3.无参构造方法注入
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//调用 BeanDefinition属性合并完成后的 BeanPostProcessor后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//被@Autowired、@Value标记的属性在这里获取
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//向容器中缓存单例模式的Bean对象,以防循环引用
//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
//这里判断的逻辑主要有三个:
//1.是否为单例
//2.是否允许循环引用
//3.是否是在创建中的bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
//getEarlyBeanReference,从二级缓存中取出实例化但没有属性赋值的bean
//加入到三级缓存objectFactory中,通过getObject获取上述的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//Bean对象的初始化,依赖注入在此触发
Object exposedObject = bean;
try {
//填充Bean实例的属性
populateBean(beanName, mbd, instanceWrapper);
//初始化bean,过程如下:
//1:判断景否实现了BeanNameAware,BeanClassloaderAware,
//BeanFactoryAware方法,如果有,则设置相关的属性
//2:调用bean初始化的前置(BeanPostProcessor)操作
//3:执行初始化的方法。
//如果有initializingBean,则调用afterPropertiesSet
//如果有InitMethod,则调用初始方法
//4:调用bean初始化的后置(BeanPostProcessor)操作
exposedObject = initializeBean(beanName, exposedObject, mbd);
//....................
//....................
在这个方法中,bean才是真正的创建:
- 首先调用
createBeanInstance()
方法,通过反射
创建一个bean实例(依赖还未注入) - 然后调用
applyMergedBeanDefinitionPostProcessors()
方法,判断实例中被@Autowire标记的成员变量或者方法并记录下来 - 调用
addSingletonFactory()
方法,将bean加入到三级缓存中,解决单例模式下的循环依赖问题 - 调用
populateBean()
方法,根据2中被记录下来的成员变量进行注入 - 调用
initializeBean()
方法,执行初始化方法的前置操作——执行初始化方法操作——执行初始化方法的后置操作
到这里,bean的创建就已经完成,下面来讲讲单例模式下是怎么解决循环依赖问题的
单例模式下是怎么解决循环依赖问题的
同样的,假设A、B(单例)相互依赖,创建A的过程中,在属性注入之前,也就是和上面的2步骤,调用addSingletonFactory()方法👇——第二个参数是ObjectFactory,一个只定义了getObject()方法的接口。这里用了匿名内部类,调用getEarlyBeanReference()
方法(跟进方法中可以看到依然存在一个bean的后置处理器SmartInstantiationAwareBeanPostProcessor
的调用,如果不存在则返回默认的实例)返回实例的值,加入到三级缓存中。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- 当A执行到属性注入的时候,通过getBean去获取B的实例,B此时还不存在,所以也进入到了doCreateBean中,B的实例也加入到了三级缓存中
- 当B去给属性注入的时候,通过getBean去获取A的实例,就会去调用
getSingleton()
方法,依次从一级缓存–二级缓存–三级缓存中获取,最后从三级缓存中获取到了A的实例,即使这时候它是没有完全初始化的 - 然后B初始化完成了,则回到了A的属性注入,后面的步骤就没什么了。