跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

SpringBoot 源码解析:AnnotationConfigServletWebServerApplicationContext 构造

SpringBoot 应用上下文初始化过程中,AnnotationConfigServletWebServerApplicationContext 构造方法主要负责两个核心组件的初始化。一是注解 Bean 定义读取器,通过注册 ConfigurationClassPostProcessor 等后置处理器来处理 @Configuration、@Autowired 等注解;二是类路径 Bean 定义扫描器,配置默认过滤器以扫描@Component 等组件注解。这一过程涉及 BeanDefinitionRegistry 接口的使用、Environment 对象的获取以及默认 Bean 工厂的属性设置,为后续 Bean 的加载与依赖注入奠定基础。

奶糖兔发布于 2026/4/7更新于 2026/5/2919 浏览
SpringBoot 源码解析:AnnotationConfigServletWebServerApplicationContext 构造

SpringBoot 源码解析:应用上下文构造流程

在 SpringBoot 启动流程中,创建应用程序上下文是核心环节之一。本文聚焦于 createApplicationContext() 方法的具体实现,深入分析 AnnotationConfigServletWebServerApplicationContext 的初始化过程。

源码入口

在 SpringApplication.run() 方法的执行逻辑中,第 6 步负责创建应用程序上下文:

// SpringApplication 类方法
public ConfigurableApplicationContext run(String... args) {
    // ... 前置步骤 ...
    // 6. 创建应用程序上下文
    context = createApplicationContext();
    // ... 后续步骤 ...
}

核心代码即实例化 AnnotationConfigServletWebServerApplicationContext:

public class AnnotationConfigServletWebServerApplicationContext 
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;

    public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
}

这里初始化了两个关键组件:注解 Bean 定义读取器(reader)和类路径 Bean 定义扫描器(scanner)。它们都接收当前上下文实例作为参数,用于后续的 Bean 注册与管理。

一、初始化注解 Bean 定义读取器

AnnotatedBeanDefinitionReader 负责处理带有注解的配置类。其构造函数主要完成三件事:获取注册表、获取环境对象、注册配置处理器。

1. Bean 定义注册接口

构造时传入的 this 即为 AnnotationConfigServletWebServerApplicationContext,它实现了 BeanDefinitionRegistry 接口。该接口是容器管理 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) {
    if (registry instanceof EnvironmentCapable) {
        return ((EnvironmentCapable) registry).getEnvironment();
    }
    return new StandardEnvironment();
}

3. 注册注解配置处理器

这是初始化的关键步骤。系统会自动注册一系列后置处理器(PostProcessor),用于处理不同类型的注解。

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        // 设置依赖比较器,支持 @Order 注解排序
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        // 设置自动注入候选解析器
        if (!(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;
}

这些处理器主要用于框架内部,角色被标记为 ROLE_INFRASTRUCTURE(基础设施),用户通常无需干预。

二、初始化类路径 Bean 定义扫描器

ClassPathBeanDefinitionScanner 负责扫描指定包路径下的组件,将其转换为 Bean 定义并注册到容器中。

1. 注册默认注解过滤器

扫描器初始化时会加载默认过滤器,确保能识别常见的 Spring 组件注解。

protected void registerDefaultFilters() {
    // 添加 @Component 注解的过滤器
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    
    // 尝试加载 JSR-250 和 CDI 相关注解,若存在则支持
    try {
        this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
    } catch (ClassNotFoundException ex) { /* 忽略 */ }
    
    try {
        this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
    } catch (ClassNotFoundException ex) { /* 忽略 */ }
}

这意味着带有 @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());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

            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;
}

在此过程中,系统会处理作用域元数据、生成 Bean 名称、应用代理模式,并最终将 Bean 定义注册到容器的 beanDefinitionMap 缓存中。

总结

AnnotationConfigServletWebServerApplicationContext 的构造过程主要完成了两件事:

  1. 初始化注解 Bean 定义读取器:注册各类后置处理器(如 ConfigurationClassPostProcessor, AutowiredAnnotationBeanPostProcessor 等),为后续注解解析打下基础。
  2. 初始化类路径 Bean 定义扫描器:配置默认过滤器,准备扫描指定包路径下的组件并将其注册为 Bean。

这两个组件构成了 SpringBoot Web 应用上下文的基石,确保了从配置类解析到组件扫描的全流程顺畅运行。

目录

  1. SpringBoot 源码解析:应用上下文构造流程
  2. 源码入口
  3. 一、初始化注解 Bean 定义读取器
  4. 1. Bean 定义注册接口
  5. 2. 获取环境对象 Environment
  6. 3. 注册注解配置处理器
  7. 二、初始化类路径 Bean 定义扫描器
  8. 1. 注册默认注解过滤器
  9. 2. 自定义包扫描
  10. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • LLM 大模型实践指南:从入门到应用开发路线
  • OpenClaw ACP 协议:IDE 直接驱动 AI Agent
  • 基于Termux的Android平台OpenClaw部署方案
  • 毕业论文智能写作工具功能与使用流程解析
  • Faster-Whisper-GUI 日语语音识别异常问题排查与修复
  • OpenClaw 本地部署教程:环境配置、插件开发与问题排查
  • 2026 年十大 AI 编程工具推荐
  • Java 经典排序算法全解析
  • 基于 AI 辅助的高校宿舍管理系统设计与实现
  • Python 内置函数深度解析:tuple()与 type() 实用指南
  • GitHub 访问加速方案:5 种常用提速方法
  • MC.JS WEBMC1.8 十分钟搭建简易方块世界
  • Python 基础入门指南
  • OpenClaw 20 个精选 Skills 使用指南与最佳实践
  • C++11 手写 Promise 实现与 std::promise 对比
  • Python vs Java:AI 项目选型对比与实战建议
  • 五大 AI 工具实战指南:豆包、即梦、剪映、飞书与扣子
  • Gitea 轻量级自建 Git 服务安装与入门
  • HTB Fries 靶机实战:从 Gitea 凭据泄露到 AD CS 证书攻击
  • AI 赋能原则 6 解读:深度专业与跨界能力的复合竞争力

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online