前言
在之前的系列文章中,我们梳理了 SpringApplication 的启动流程,了解了引导上下文、环境准备以及 Bean 工厂的核心组件功能。接下来,我们将深入探讨应用上下文的构造方法,这是 Spring Boot 启动过程中承上启下的关键环节。
本文基于 Spring Boot 2.7.18 版本,重点分析 createApplicationContext() 方法中创建的应用上下文对象及其初始化逻辑。
源码入口
整个启动流程的第 6 步是创建应用程序上下文,核心代码位于 SpringApplication 类的 run 方法中:
// SpringApplication 类方法
public ConfigurableApplicationContext run(String... args) {
// ... 前置步骤省略 ...
// 6. 创建应用程序上下文
context = createApplicationContext();
// ... 后续步骤省略 ...
}
这里调用的默认实现会实例化 AnnotationConfigServletWebServerApplicationContext。这个类不仅实现了 ApplicationContext 接口,还集成了 Servlet Web Server 的功能,是 Spring Boot Web 应用的标准上下文类型。
无参构造逻辑
当我们查看 AnnotationConfigServletWebServerApplicationContext 的无参构造函数时,会发现它主要做了两件事:初始化注解 Bean 定义读取器和初始化类路径 Bean 定义扫描器。
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
// 用于读取注解的 Bean 定义读取器
private final AnnotatedBeanDefinitionReader reader;
// 用于扫描类路径并注册 Bean 定义的扫描器
private final ClassPathBeanDefinitionScanner scanner;
public AnnotationConfigServletWebServerApplicationContext() {
// 初始化注解 Bean 定义读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
// 初始化类路径 Bean 定义扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
这里的 this 传入子构造器,实际上就是当前应用上下文实例本身。这意味着读取器和扫描器将直接操作当前的容器环境。
一、初始化注解 Bean 定义读取器
AnnotatedBeanDefinitionReader 负责处理带有注解的配置类,将其转换为 Bean 定义并注册到容器中。其构造过程涉及三个关键步骤:获取注册表、获取环境对象、注册后置处理器。
1. Bean 定义注册接口
构造器接收一个 BeanDefinitionRegistry 参数,这通常就是当前的应用上下文。该接口是 Spring 容器管理 Bean 定义的核心,支持动态注册、移除和查询。
public interface BeanDefinitionRegistry extends AliasRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
void removeBeanDefinition(String beanName);
BeanDefinition getBeanDefinition(String beanName);
// ... 其他方法
}
2. 获取环境对象 Environment
环境对象提供了配置属性访问能力。如果注册表本身实现了 EnvironmentCapable 接口,则直接从中获取;否则创建一个标准的 StandardEnvironment。
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry instanceof EnvironmentCapable) {
return ((EnvironmentCapable) registry).getEnvironment();
}
return new StandardEnvironment();
}
3. 注册注解配置处理器
这是构造过程中最重要的一步。系统会自动注册一系列的后置处理器(PostProcessor),用于处理各种注解逻辑。这些处理器会在后续的 Bean 生命周期中被调用。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 获取默认的 ListableBeanFactory 对象
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
// 设置依赖比较器,支持 @Order 注解排序
if (beanFactory != null && !(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
// 设置自动注入候选解析器,处理 @Autowired 等
if (beanFactory != null && !(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册 ConfigurationClassPostProcessor,处理 @Configuration、@Bean 等
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 AutowiredAnnotationBeanPostProcessor,处理 @Autowired、@Value
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 CommonAnnotationBeanPostProcessor,处理 @Resource、@PostConstruct
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 EventListenerMethodProcessor,处理 @EventListener
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
return beanDefs;
}
3.1 获取默认 Bean 工厂
通过 unwrapDefaultListableBeanFactory 方法,从注册表中提取出 DefaultListableBeanFactory 实例。这是 Spring 内部实际管理 Bean 定义和生命周期的核心容器。
@Nullable
private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
if (registry instanceof DefaultListableBeanFactory) {
return (DefaultListableBeanFactory) registry;
} else if (registry instanceof GenericApplicationContext) {
return ((GenericApplicationContext) registry).getDefaultListableBeanFactory();
}
return null;
}
拿到工厂后,设置了两个重要属性:
AnnotationAwareOrderComparator:支持@Order注解的依赖排序比较器。ContextAnnotationAutowireCandidateResolver:处理@Autowired等注解的自动注入候选者解析器。
3.2 注册后置处理器
上面创建的 RootBeanDefinition 都是框架内部使用的基础设施 Bean,角色被设置为 ROLE_INFRASTRUCTURE(值为 2)。用户自定义的 Bean 默认为 ROLE_APPLICATION(值为 0)。
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
这些处理器包括:
ConfigurationClassPostProcessor:处理配置类注解。AutowiredAnnotationBeanPostProcessor:处理依赖注入。CommonAnnotationBeanPostProcessor:处理 JSR-250 标准注解。EventListenerMethodProcessor:处理事件监听。
二、初始化类路径 Bean 定义扫描器
ClassPathBeanDefinitionScanner 负责扫描指定包路径下的组件类,并将其注册为 Bean 定义。
1. 注册默认注解过滤器
扫描器在构造时会注册默认的过滤规则,确保能识别常见的 Spring 组件注解。
protected void registerDefaultFilters() {
// 添加 @Component 注解的过滤器
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
// 尝试加载 JSR-250 ManagedBean 注解
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
} catch (ClassNotFoundException ex) {
// 忽略不存在的 API
}
// 尝试加载 JSR-330 Named 注解
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
} catch (ClassNotFoundException ex) {
// 忽略不存在的 API
}
}
这意味着带有 @Component、@Controller、@Service、@Repository 的类都会被纳入扫描范围。
2. 自定义包扫描
当调用 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) {
// 查找当前包路径下符合条件的候选组件
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析作用域元数据
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成 Bean 名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 后处理 Bean 定义
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查并注册
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;
}
这个过程确保了用户编写的业务组件能够被正确识别、命名并注册到 Spring 容器中。
总结
本文详细拆解了 AnnotationConfigServletWebServerApplicationContext 的构造过程。核心在于初始化两个组件:
- 注解 Bean 定义读取器:负责注册框架内部的后置处理器,如
ConfigurationClassPostProcessor和AutowiredAnnotationBeanPostProcessor,为后续注解解析打下基础。 - 类路径 Bean 定义扫描器:负责扫描指定包路径,识别
@Component等注解组件,并将其转换为 Bean 定义注册到容器。
这两个组件的初始化标志着 Spring Boot 应用上下文的基本就绪,为后续的刷新(Refresh)和 Bean 加载做好了准备。


