测试Bean
1.容器启动
Spring创建一个容器有多种方式,可以基于配置类,也可以基于xml配置文件,这里使用XML配置的方式创建Spring容器
Debug走起,打下第一个断点
来到 org.springframework.context.support.AbstractApplicationContext.refresh() 方法 refresh是spring容器启动最核心的方法
在这个方法内一共调用了其他12个方法 , 这篇是看Bean的生命周期,所有无关的方法浅浅过一下
第一个方法 prepareRefresh()
// Prepare this context for refreshing.
prepareRefresh();
接下来执行了这一行代码 做了一件非常重要的事情,创建BeanFactory
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
2. 创建BeanFactory
我们来看下是怎么获取bean工厂的
debug跟进 org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
返回的bean工厂类型为 DefaultListableBeanFactory
如果你下载了源码 可以看到在 BeanFactory 接口注释的全套 bean 生命周期接口 等会我们能在源码中全部看到
Bean 工厂实现应尽可能支持标准的 bean 生命周期接口。全套初始化方法及其标准顺序为:
-
BeanNameAware’s setBeanName
-
BeanClassLoaderAware’s setBeanClassLoader
-
BeanFactoryAware’s setBeanFactory
-
EnvironmentAware’s setEnvironment
-
EmbeddedValueResolverAware’s setEmbeddedValueResolver
-
ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)
-
ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)
-
MessageSourceAware’s setMessageSource (only applicable when running in an application context)
-
ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)
-
ServletContextAware’s setServletContext (only applicable when running in a web application context)
-
postProcessBeforeInitialization methods of BeanPostProcessors
-
InitializingBean’s afterPropertiesSet
-
a custom init-method definition
-
postProcessAfterInitialization methods of BeanPostProcessors
在关闭 bean 工厂时,将应用以下生命周期方法:
- postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
- DisposableBean’s destroy
- a custom destroy-method definition
回到 org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory
在创建bean工厂后,又调用了三个方法
方法一:设置序列化ID
beanFactory.setSerializationId(getId());
方法二:定制bean工厂 (bean定义是否可以被覆盖,是否运行循环依赖)
customizeBeanFactory(beanFactory);
方法三: 解析bean配置信息,生成BeanDefinitions (下文都将简称为bd)
loadBeanDefinitions(beanFactory);
3.解析生成 BeanDefinitions
debug跟进 来到 org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions()
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
创建一个xml解析器,我们使用的xml配置文件启动容器,bean的定义信息都配置在xml中
解析完成后调用 loadBeanDefinitions(beanDefinitionReader)方法,添加到BeanDefinition中
接下来获取所有的配置信息文件,加载
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
最终将xml配置文件通过JDK中的JAXP解析为Document对象,然后再注册为bd
注册完bd后,beanFactory中的beanDefinitionMap已经有了bean A的 定义信息 ,将来就可以通过这些定义信息,通过反射实例并初始化一个bean A放到容器中
接下来来到 invokeBeanFactoryPostProcessors(beanFactory)方法 进入执行Bean工厂的后置处理器流程
4.执行Bean工厂的后置处理器方法
Bean工厂的后置处理器方法的执行时机为 初始化bean工厂,并且解析生成bd后,但在bean实例化前
再接着 refresh方法往下走,到第十一个方法 开始进入bean的实例化阶段
finishBeanFactoryInitialization(beanFactory)
5.实例化bean前 applyBeanPostProcessorsBeforeInstantiation 扩展点
来到 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization
又调用了 beanFactory.preInstantiateSingletons(); 进行初始化所有的单实例Bean
org.springframework.beans.factory.support.DefaultListableBeanFactory. preInstantiateSingletons()
首先复制了所有的beanName,放到beanNames中
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
然后就开始遍历所有的beanName
for (String beanName : beanNames) {
.....
}
遍历的第一步就是将bd转为RootBeanDefinition统一
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
接着就是一个三连判断 不能是抽象类,必须是单例,且不是懒加载,继续往下走
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
判断是不是工厂bean 测试的bean A是一个普通bean,走else
if (isFactoryBean(beanName))
调用getBean(beanName);方法
又调用 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean
首先获取真正的beanName 去掉工厂bean名称的&前缀以及解析 bean别名
String beanName = transformedBeanName(name);
然后尝试从缓存中拿bean对象
Object sharedInstance = getSingleton(beanName)
来到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton
首先注意一个方法调用的参数
allowEarlyReference 这个参数的值,默认就是true,用来解决循环依赖的,很重要
接着看这个方法 从一级缓存中拿,一级缓存中都是以及初始化好的单例bean,如果能拿到,直接返回
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256) 单例缓存池(一级缓存)
Object singletonObject = this.singletonObjects.get(beanName); //singletonObjects 单例缓存池
如果没拿到,并且当前beanName对应的bean正在创建中
private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)) 保存正在创建的beanName
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
在从二级缓存 earlySingletonObjects 中找
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16) 二级缓存,实例化,但未属性填充的bean
singletonObject = this.earlySingletonObjects.get(beanName);
没找到继续从三级缓存 singletonObjects 中找
**private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16) 存储生成代理对象的lombda表达式 **
注意这个map的value ObjectFactory<?> 是一个函数式接口,将来用以保存lombda表达式 ,用来解决被AOP代理的bean循环依赖问题
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
如果singletonFactory不为空, 将执行 lombda表达式,生成代理类,也就是提前AOP
singletonObject = singletonFactory.getObject();
提前AOP后,又执行了两个有意思的方法
把当前的代理类对象放到二级缓存中,然后删除三级缓存中的entry,这两步非常重要,之后会写一篇循环依赖的博文,在详细说
如果从缓存中都没拿到,直接返回空对象
循环依赖判断,没有循环依赖问题往下走,有循环依赖的对象先创建依赖的对象
当前的bean是单例的,进入if
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
这里调用了一个 getSingleton 方法 方法有两个参数,一个beanName,还有一个lombda表达式,
执行org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法
首先校验bean的名字不能为空
Assert.notNull(beanName, "Bean name must not be null");
然后再次尝试从缓存中拿对象 上面进去看过了
Object singletonObject = this.singletonObjects.get(beanName);
没拿到进入if判断 执行lombda表达式
执行 createBean(beanName, mbd, args); 方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
在bean真正实例化前,还有这么一个方法 能让当前返回代理对象,而不是目标bean对象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)
判断容器中是否有InstantiationAwareBeanPostProcessors,如果有,执行InstantiationAwareBeanPostProcessors.applyBeanPostProcessorsBeforeInstantiation方法
实例化之前会调用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
如果有返回对象,改对象将被放到spring容器中,而当前bd封装定义信息所属bean的实例化流程将提前终止,并且执行InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsAfterInitialization 方法
如果返回null,当前bean实例化流程继续往下走
我们没有实现applyBeanPostProcessorsBeforeInstantiation扩展点,继续往下走
来到doCreateBean(beanName, mbdToUse, args)方法
doCreateBean(beanName, mbdToUse, args)
bean实例化前的流程已经完成,开始真正实例化bean了 放到下篇博文