Bean的生命周期源码解析上
Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。
Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的。
Bean生命周期流程图:https://www.processon.com/view/link/5f8588c87d9c0806f27358c1
Bean的生成过程
根据上面流程图,要想生成bean,首先要生成对应的BeanDefinition
生成BeanDefinition
扫描流程
在生成BeanDefinition之前,肯定是 需要扫描哪些类需要生成BeanDefinition。AnnotationConfigApplicationContext
的scan
的doScan
。就是主要扫描过程。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//核心的扫描逻辑 把扫描到的符合条件的类生成BeanDefinition的集合
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//获取scope的属性值(是单例的还是原型的)
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置bean的名称
// 大致过程就是判断有没有org.springframework.stereotype.Component注解,有的话就获取value
// 如果获取不到value值就构建一个默认的名称。默认构建过程中会对类名做字符串处理,返回一个beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//设置一些默认值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 处理@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//判断beanName是否已经存在
if (checkCandidate(beanName, candidate)) {
//判断通过后将BeanDefinition和beanName 封装成definitionHolder对象
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//最终会把definitionHolder中的BeanDefinition取出,和beanName 存入到beanDefinitionMap当中
//到这里扫描主要的流程基本结束
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
从上面代码来看 扫描过程主要分为这个部分
- 根据一定的逻辑扫描特定的资源然后以
Set<BeanDefinition>
形式返回 - 循环解析BeanDefinition 获取对应的scope、beanName、一些注解的处理等等
- 经过一些列处理将符合要求的
BeanDefinition
封装成BeanDefinitionHolder
- 最后把
BeanDefinitionHolder
中的BeanDefinition
和beanName 存入到beanDefinitionMap
中
来看第一步 扫描的逻辑Set<BeanDefinition> candidates = findCandidateComponents(basePackage)
该方法中主要的是scanCandidateComponents(basePackage)
这个方法。这一部分是扫描的核心部分
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源 CLASSPATH_ALL_URL_PREFIX的值是classpath*:
//this.resourcePattern的值是**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//获取classpath* 下包路径下的所有**/*.class 的资源
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
//解析每个资源文件
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
//通过Resource获取类的元数据信息(包含类名、属性、注解等等)
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// excludeFilters、includeFilters判断、@Conditional的条件判断
if (isCandidateComponent(metadataReader)) {
//当判断是一个bean之后,创建一个ScannedGenericBeanDefinition
//这个构造方法中把setBeanClassName(this.metadata.getClassName())放入到BeanDefinition中
// 从metadataReader获取到getAnnotationMetadata--AnnotationMetadata
// 放入到ScannedGenericBeanDefinition 提过给第二次判断
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
//在后续过程中,当beanName相同是会通过Source判断是否兼容
sbd.setSource(resource);
//第二次判断 判断独立性、接口等等
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
这一部分的扫描流程是:通过ASM技术解析每个class文件封装成Source对象,遍历每个Resource对象,通过MetadataReader获取到元数据信息。isCandidateComponent(metadataReader)
底层是进行excludeFilters和includeFilters,以及条件注解@Conditional的筛选。筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition。这个过程中把类名放入Object beanClass
中。接着isCandidateComponent(sbd)
基于ScannedGenericBeanDefinition判断这个class是不是接口或者抽象类等情况。如果不是接口也不是抽象类的话通过candidates.add(sbd);
加入到集合当中
第二步,扫描核心逻辑结束后拿到BeanDefinition集合后,循环处理BeanDefinition。获取BeanDefinition的scope属性,根据BeanDefinition获取到beanName,对BeanDefinition设置一些默认值,判断BeanDefinition有没有@Lazy、@Primary等注解。最后判断beanName是否已经存在。
第三步 通过上述对BeanDefinition的处理后,把满足条件的BeanDefinition封装成BeanDefinitionHolder
第四步 registerBeanDefinition(definitionHolder, this.registry)
解析BeanDefinitionHolder,从BeanDefinitionHolder中获取到beanName和BeanDefinition放入到beanDefinitionMap 当中。到此整个扫描流程基本结束。
Spring扫描底层流程:https://www.processon.com/view/link/61370ee60e3e7412ecd95d43
合并BeanDefinition
扫描完成后接下来看AnnotationConfigApplicationContext的refresh()方法,先来看finishBeanFactoryInitialization(beanFactory);
这行代码,主要是创建非懒加载的单例bean。该方法里面的核心方法beanFactory.preInstantiateSingletons();
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
//扫描的时候会把beanName放入到List当中
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//这行代码开始合并BeanDefinition并且获取合并后的BeanDefinition
// 在spring中支持父子BeanDefinition 子BeanDefinition需要从父BeanDefinition中获取信息
// 因此创建子BeanDefinition对应的bean时需要进行父子BeanDefinition合并,得到完整子的BeanDefinition也就是RootBeanDefinition
// 同时把RootBeanDefinition放入到Map<String, RootBeanDefinition>中
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//当合并后的BeanDefinition 符合单例bd.isSingleton()
// 非懒加载!bd.isLazyInit() 非抽象!bd.isAbstract() 时 最后调用getBean(beanName)
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 获取FactoryBean对象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
//判断是否开启安全管理器 不用管 直接看else的代码
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
//判断这个bean是否实现的是SmartFactoryBean接口 如果实现了 在判断是否重写了isEagerInit,默认返回false
//如果重写了isEagerInit 并且放回true 则调用getBean创建对象
//SmartFactoryBean 是 FactoryBean的子接口
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 创建真正的Bean对象(getObject()返回的对象)
getBean(beanName);
}
}
}
else {
// 创建Bean对象
getBean(beanName);
}
}
}
// 所有的非懒加载单例Bean都创建完了后
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
//当单例bean创建好之后会放入到单例池当中,而下面这个方法就是从单例池当中获取单例bean
Object singletonInstance = getSingleton(beanName);
//判断单例bean有没有实现SmartInitializingSingleton接口 有的话调用重写的方法(afterSingletonsInstantiated)
//注意afterSingletonsInstantiated方法是在所有单例bean都创建好之后,才开始调用每一个实现了SmartInitializingSingleton接口的方法
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
//调用重写SmartInitializingSingleton接口的方法
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
通过扫描得到所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了。但是在Spring中支持父子BeanDefinition,类似于
这么定义的情况下,child是单例Bean
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
这么定义的情况下,child就是原型Bean
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
所以需要进行BeanDefinition的合并,得到完整的BeanDefinition。合并完BeanDefinition后会得到RootBeanDefinition,根据这个RootBeanDefinition判断是否懒加载,抽象类等等,最后通过getBean(beanName)
方法创建非懒加载的单例bean。所有的bean都创建完成后判断有没有实现SmartInitializingSingleton
接口 如果有的话调用afterSingletonsInstantiated
方法 。
下一篇会对getBean(beanName)
方法进行分析。到目前为止,从spring的源码中可以学习到两个扩展点,一个是扫描逻辑里面有一个判断@Conditional的注解,一个是bean 实现SmartInitializingSingleton
接口 重写afterSingletonsInstantiated
。
扩展点案例
@Conditional
@Service
@Conditional(GoodsConditional.class)
public class GoodsServiceImpl {
public void test(){
System.out.println("GoodsServiceImpl---------test");
}
}
//如果返回false 表示不创建该bean,返回true表示创建该bean 所以可以在这里写判断逻辑
public class GoodsConditional implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
System.out.println("11111");
return true;
}
}
SmartInitializingSingleton
@Service
@Conditional(GoodsConditional.class)
public class GoodsServiceImpl implements SmartInitializingSingleton {
public void test(){
System.out.println("GoodsServiceImpl---------test");
}
@Override
public void afterSingletonsInstantiated() {
System.out.println("创建完成单例bean后:执行了GoodsServiceImpl 的 afterSingletonsInstantiated 方法");
}
}
测试
//扫描该路径
@ComponentScan("service")
public class AppConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Object obj = context.getBean("goodsServiceImpl");
GoodsServiceImpl goodsService = (GoodsServiceImpl)obj;
goodsService.test();
}
}