Spring之Bean生命周期源码解析(一)
Spring之Bean生命周期源码解析(一)
- Bean生命周期流程
- Bean包扫描底层流程
- MetadataReader
- 合并BeanDefinition
- 加载类
什么是Bean的生命周期
Bean的生命周期就是指: Spring中,一个Bean从生成到销毁的过程
Bean生命周期流程图
Bean的生命周期:
- 启动ApplicationContext
- 创建BeanFactory
- 初始化BeanFactory
- 在BeanFactory后置处理:在这里会进行包扫描,找到所有符合条件的class文件
- 生成BeanDefition
- 合并BeanDefinition
- 加载类
- 实例化前
- 实例化
- 推断构造
- 实例化
- BeanDefinition的后置处理
- 实例化后
- 填充属性
- 填充属性后
- 执行Aware回调接口
- 初始化前
- 初始化
- 初始化后
- Bean销毁
Bean包扫描底层流程图
Spring启动的时候会进行包扫描,会先调用ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)
去扫描某个包路径,并且将需要的class文件解析成BeanDefinition然后放到一个set集合中.
Spring包扫描底层流程:
- 首先通过ResourcePatternResolver获得指定包路径下的所有.class文件(在Spring源码中,会把此文件包装成Resouce对象)
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// Class文件的File对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
- 遍历每个Resource对象
for (Resource resource : resources) {
...
}
- 利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体的实现类为SimpleMetadataReader)
// 从class文件中获取类元数据信息,比如注解信息,接口信息等,底层采用了ASM技术,这里就相当于这个类的代表
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
-
利用MetadataReader进行excludFilters和includeFilters,以及条件注解@Conditional的筛选(对于@Conditional条件注解,并不是理解为某个类上加了这个注解就匹配了而是如果存在了就会调用注解所指定类的match方法进行匹配,匹配成功就通过筛选了,否则就会排除掉),对于加了@Component注解的类,默认是被包含在includeFilters中的,除非自行加了excludeFilter条件去进行排除在外
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { // 如果被排除过滤器匹配了就不是Bean for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return false; } } // Spring里面默认就会添加一个includeFilter // 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, getMetadataReaderFactory())) { return isConditionMatch(metadataReader); } } return false; }
-
筛选通过之后,基于MetadataReader生成ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
-
基于MetadataReader判断是对应的类是不是接口或抽象类
-
如果不是一个独立的类比如说是一个普通的内部类,就不能成为一个Bean,
-
如果是顶级类或者静态内部类就是独立的
-
如果是接口或者抽象类,也不能成为一个Bean
-
如果是抽象类但是包含了@LookUp就是一个独立的类
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { AnnotationMetadata metadata = beanDefinition.getMetadata(); return (metadata.isIndependent() && (metadata.isConcrete() || (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); }
-
-
如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入到Set集合中
if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); }
MetadataReader
MetadataReader表示类的元数据读取器,主要包含一个AnnotationMetadata,功能有:
- 获取类的名字
- 获取父类的名字
- 获取所实现的所有接口
- 获取所有内部类的名字
- 判断是不是抽象类
- 判断是不是一个接口
- 判断拥有某个注解的方法集合
- 获取类上添加的所有注解信息
- 获取类上的所有注解类型集合
注意: CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用了ASM,并没有加载这个类到JVM内存中去,并且最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储的是当前类的名字,而不是class对象.(beanClass属性的类型是Object,它既可以存储类的名字,也可以存储class对象)
除了可以通过扫描得到BeanDefinition对象,我们还可以直接通过bean标签的形式去定义或者@Bean注解
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
...
/**
* 为什么这里是Object,而不是Class<?>
* 因为这里还没有加载,只是通过ASM技术去解析了这个类,并没有去解析,只是把这个类的名字设置给了BeanDefinition的属性,当创建这个Bean的时候,才会去真正加载
*/
@Nullable
private volatile Object beanClass;
}
合并BeanDefinition
通过扫描得到的所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在Spring中支持父子BeanDefintion,和Java父子类类似,但是不是一回事.
如如下情况,child无疑是单例bean
<bean id="parent" class="linc.cool.service.Parent" scope="prototype"/>
<bean id="child" class="linc.cool.service.Child" />
但是如下情况,child继承了parent的属性,成为了原型bean
<bean id="parent" class="linc.cool.service.Parent" scope="prototype"/>
<bean id="child" class="linc.cool.service.Child" parent="parent" />
而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition
(Spring源码中合并后的BeanDefinition是RootBeanDefinition,对应的合并逻辑在AbstractBeanFactory#getMergedBeanDefinition)
加载类
BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化对象就必须先去加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory#createBean方法中一开始会调用resolveBeanClass(mbd, beanName) 去进行判断
如果beanClass属性的类型是Class,那么就直接返回,否则,就会根据类名进行加载
后续就是通过AbstractBeanFactory#doResolveBeanClass去进行加载了,其中会利用BeanFactory所设置的类加载器来加载类
如果没有设置,就默认使用AbstractBeanFactory#ClassUtils.getDefaultClassLoader() 所返回的类加载器去加载类
// 如果beanClass被加载了,就直接返回,加载了的话存的是Class
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
// 如果beanClass没有被加载
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
// 去进行类加载
return doResolveBeanClass(mbd, typesToMatch);
}
public boolean hasBeanClass() {
return (this.beanClass instanceof Class);
}
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
ClassUtils.getDefaultClassLoader()
- 优先返回当前线程中的ClassLoader
- 线程中类加载为null的情况下,返回ClassUtils类的类加载器
- 如果ClassUtils的类加载器为空,那么则表示是BootStrap类加载器加载的ClassUtils类,那么久返回系统类加载器
@Nullable
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
// 优先获取线程中的类加载器
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
// 线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器
if (cl == null) {
// No thread context class loader -> use class loader of this class.
// 默认使用AppClassLoader
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
// 加入ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
转载自:https://juejin.cn/post/7109030745795985445