Spring Bean生命周期
本文基于图灵课堂周瑜老师的讲解整理,包括spring bean加载的过程,主要是扫描BeanDefinition以及初始化非懒加载单例Bean两部分,源码取自SpringFramework 5.3.22
1. Bean扫描
本小节介绍的是Spring从给定的扫描位置扫描到待加载的Bean,生成BeanDefinitionMap的过程
SpringBoot启动过程中使用的ApplicationContext是AnnotationConfigApplicationContext
,而它初始化的时候会顺带初始化两个BeanDefinitionReader
:AnnotatedBeanDefinitionReader
和ClassPathBeanDefinitionScanner
,前者是可以直接通过给定的class注册Bean,后者则可以扫描给定目录下所有的目标Bean,下面着重介绍后者扫描Bean组件的过程。
ClassPathBeanDefinitionScanner
扫描的入口是public int scan(String… basePackages),而真正做事情的是protected Set<BeanDefinitionHolder> doScan(String… basePackages)方法,代码如下:
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
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) {
// 找到basePackage下的所有候选组件,这里只是把classname赋值给了BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 获取组件的scope,默认是单例的
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 获取beanname
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 处理通用的注解
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 最后再对BeanDefinition做检查,看下是否有重名的
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}