前言
本节将正式介绍Spring源码细节,将讲解Bean生命周期。请注意,虽然我们不希望过于繁琐地理解Spring源码,但也不要认为Spring源码很简单。在本节中,我们将主要讲解Spring 5.3.10版本的源代码。如果您看到的代码与我讲解的不同,也没有关系,因为其中的原理和业务逻辑基本相同。为了更好地理解,我们将先讲解Bean的生命周期,再讲解Spring的启动原理和流程,因为启动是准备工作的一部分。
题外话
目前在该版本中,引入了一个名为jfr的JDK技术,类似于Java飞行日志(JFL),也称为飞行数据记录器(Black Box)技术。具体作用不再详细阐述,读者可以参考此文:JFR介绍
如果您看到以下代码,请直接跳过,因为它并没有太大的作用:
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
需要注意的是,其中的 StartupStep
关于默认实现并没有什么实际作用。但是,还有一种实现方式是 FlightRecorderStartupStep
,它是JDK的JFR技术。
Bean的生成过程
生成BeanDefinition
BeanDefinition的作用大家基本通过前面的文章也知道了大概,就是用来描述bean的。
那么它是如何加载的呢?首先我们看一下 ClassPathBeanDefinitionScanner
类,它是用于扫描的。其中有一个属性是 BeanDefinitionRegistry
,即Bean定义的注册类。默认实现是 DefaultListableBeanFactory
,但是在 ClassPathBeanDefinitionScanner
类中并没有直接使用该类作为属性,而是使用了它的父接口 BeanDefinitionRegistry
。这是因为 ClassPathBeanDefinitionScanner
类实际上并没有使用 BeanDefinitionRegistry
接口中的许多方法来注册Bean定义。
接下来,我们来分析 ClassPathBeanDefinitionScanner
类的 scan
方法:
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) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
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);
}
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
大致逻辑如下:
- 获取扫描包路径
- findCandidateComponents:获取符合条件的bean
- 遍历candidate(候选bean),由于第二部使用了ASM技术,所以并没有真正获取beanclass而是使用了beanname替代所以,遍历的做法就是将符合条件的bean定义进行注册。
- scopeMetadata解析scope注解。
- beanNameGenerator构建当前bean的唯一名字。
- postProcessBeanDefinition这里其实就是进行默认值赋值。
- processCommonDefinitionAnnotations进行解析@Lazy、@Primary、@DependsOn、@Role、@Description
- checkCandidate(beanName, candidate)再次检查是否该beanName已经注册过。
- registerBeanDefinition,注册到我们的DefaultListableBeanFactory的BeanDefinitionMap中。
其实这里基本就已经大概了解 的差不多了,然后再继续讲解下每一个流程里面都走了那些逻辑: