Spring Boot 的注解生效详细步骤解析

 更新时间:2025年09月11日 11:21:15   作者:许苑向上  
Spring通过扫描、解析、注册分层处理配置类注解(如@Configuration、@ComponentScan等),利用递归、延迟加载和缓存机制,实现BeanDefinition的动态注册与灵活扩展,解决依赖和性能问题,本文给大家介绍Spring Boot的注解生效详细步骤解析,感兴趣的朋友跟随小编一起看看吧

在 Spring 中,@Configuration@ComponentScan@Bean@Import 等注解的扫描、解析和 BeanDefinition 注册是一个分层处理的过程。下面我们以 @Configuration为例,结合代码流程详细说明其从扫描到注册的完整逻辑。

1. 整体流程概览

以下是核心步骤的流程图:

1. 扫描候选配置类 → 2. 解析注解元数据 → 3. 注册 BeanDefinition

具体分为以下阶段:

  1. 扫描阶段:通过 BeanDefinitionRegistry 获取所有候选配置类。
  2. 解析阶段:使用 ConfigurationClassParser 解析注解(如 @ComponentScan@Bean@Import)。
  3. 注册阶段:通过 ConfigurationClassBeanDefinitionReader 将解析结果注册为 BeanDefinition

2. 详细步骤解析

2.1 扫描阶段:识别候选配置类

触发入口
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
逻辑

  1. BeanDefinitionRegistry 获取所有已注册的 BeanDefinition 名称:
    String[] beanNames = registry.getBeanDefinitionNames();
  2. 遍历这些名称,检查对应的 BeanDefinition 是否是候选配置类:
    • 条件:类上有 @Configuration@Component@ComponentScan@Import@ImportResource,或类中有 @Bean 方法。
    • 判断逻辑
      if (isFullConfigurationCandidate(beanDef) || isLiteConfigurationCandidate(beanDef)) {
          configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
      
    • isFullConfigurationCandidate(beanDef):检查是否有 @Configuration 注解。
    • isLiteConfigurationCandidate(beanDef):检查是否有其他相关注解(如 @Component@Bean 方法)。

关键点

  • 扫描的输入是已注册的 BeanDefinition(可能来自 XML、Java Config 或自动扫描)。
  • 此时尚未解析注解内容,仅识别出需要进一步处理的候选类。

2.2 解析阶段:处理注解元数据

核心类ConfigurationClassParser
入口方法parse()
逻辑:递归解析每个候选配置类的注解。

(1) 解析@ComponentScan

  • 作用:扫描指定包路径下的 @Component 类(如 @Service@Repository)。
  • 流程
    1. 获取 @ComponentScan 注解的 basePackagesbasePackageClasses
    2. 使用 ClassPathBeanDefinitionScanner 扫描类路径:
      scanner.scan(basePackages);
    3. 扫描到的类会被注册为新的 BeanDefinition(类型为 ScannedGenericBeanDefinition)。
  • 关键点
    • 扫描时使用 ASM 或反射读取类注解,避免提前加载类到 JVM。
    • 新注册的 BeanDefinition 可能也会被后续解析(如果它们也是配置类)。

(2) 解析@Bean方法

  • 作用:将配置类中的 @Bean 方法转换为 BeanDefinition
  • 流程
    1. 遍历配置类中的所有方法,筛选带 @Bean 注解的方法。
    2. 为每个 @Bean 方法生成一个 BeanDefinition
      • 类型ConfigurationClassBeanDefinition
      • 工厂方法:设置为 @Bean 方法(通过 factoryMethodNamefactoryBeanName 指定)。
      • 依赖:解析 @Bean 方法的参数(按类型或 @Qualifier 注入)。
  • 示例
    @Configuration
    public class AppConfig {
        @Bean
        public DataSource dataSource() {
            return new HikariDataSource();
        }
    }
    • 生成的 BeanDefinition 会记录:factoryBeanName=appConfig, factoryMethodName=dataSource

(3) 解析@Import

  • 作用:动态导入其他配置类或 BeanDefinition
  • 三种处理方式
    1. 普通类:直接注册为 BeanDefinition
      @Import(OtherConfig.class)
      
    2. ImportSelector:通过编程方式选择要导入的类。
      @Import(MyImportSelector.class)
      
      • MyImportSelector 实现 selectImports() 方法,返回要导入的类名数组。
    3. ImportBeanDefinitionRegistrar:直接注册 BeanDefinition
      @Import(MyRegistrar.class)
      
      • MyRegistrar 实现 registerBeanDefinitions() 方法,手动操作 BeanDefinitionRegistry

(4) 处理父类与接口

  • 递归检查配置类的父类和接口,确保不遗漏任何 @Bean 方法或元注解。

2.3 注册阶段:加载BeanDefinition

核心类ConfigurationClassBeanDefinitionReader
入口方法loadBeanDefinitions()
逻辑:将解析结果(ConfigurationClass 对象)转换为 BeanDefinition 并注册到容器。

(1) 注册@Import的类

  • 普通类:通过 registry.registerBeanDefinition() 直接注册。
  • ImportBeanDefinitionRegistrar:调用其 registerBeanDefinitions() 方法。

(2) 注册@Bean方法

  • 为每个 @Bean 方法生成 BeanDefinition 并注册:
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

(3) 处理嵌套配置类

  • 如果配置类内部有 @Configuration 静态嵌套类,递归处理。

3. 关键设计点

(1) 延迟加载与递归处理

  • 延迟加载@ComponentScan 扫描到的类可能也是配置类,需要递归解析。
  • 循环依赖处理:Spring 通过提前暴露 BeanDefinition 解决配置类之间的循环引用。

(2) 元数据存储

  • ConfigurationClass 对象存储解析后的中间结果(如 @Bean 方法、@Import 类等)。
  • BeanDefinitionattribute 字段存储配置类的元信息(如 @Lazy@Primary)。

(3) 性能优化

  • ASM 字节码分析:在扫描阶段避免加载类到 JVM。
  • 缓存:解析结果缓存到 ConfigurationClass 中,避免重复处理。

4. 示例全流程

场景

@Configuration
@ComponentScan("com.example.service")
@Import(OtherConfig.class)
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

步骤

  1. 扫描阶段
    • 发现 AppConfig 是候选配置类(有 @Configuration)。
  2. 解析阶段
    • 解析 @ComponentScan:扫描 com.example.service 包,注册 @Service 类。
    • 解析 @Import(OtherConfig.class):递归处理 OtherConfig
    • 解析 @Bean dataSource():生成工厂方法 BeanDefinition
  3. 注册阶段
    • 注册 OtherConfig 及其 @Bean 方法。
    • 注册 dataSourceBeanDefinition

5. 总结

Spring 对配置类注解的处理是一个分层递归的过程:

  1. 扫描:通过 BeanDefinitionRegistry 筛选候选类。
  2. 解析ConfigurationClassParser 解析注解并生成中间结果(ConfigurationClass)。
  3. 注册ConfigurationClassBeanDefinitionReader 将解析结果转换为 BeanDefinition

这种设计将注解元数据解析与 BeanDefinition 注册分离,确保了灵活性和扩展性(如支持动态 ImportSelector)。同时,递归处理和缓存机制解决了复杂依赖和性能问题。

到此这篇关于Spring Boot 的注解生效详细步骤解析的文章就介绍到这了,更多相关Spring Boot 注解生效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Maven在Java8下如何忽略Javadoc的编译错误详解

    Maven在Java8下如何忽略Javadoc的编译错误详解

    这篇文章主要给大家介绍了关于Maven在Java8下如何忽略Javadoc的编译错误的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-08-08
  • Java的CollectionUtils工具类详解

    Java的CollectionUtils工具类详解

    这篇文章主要介绍了Java的CollectionUtils工具类详解,CollectionUtils工具类是在apache下的,而不是springframework下的,个人觉得在真实项目中CollectionUtils,可以使你的代码更加简洁和安全,需要的朋友可以参考下
    2023-05-05
  • Java synchronized偏向锁的核心原理详解

    Java synchronized偏向锁的核心原理详解

    这篇文章主要为大家详细介绍了Java synchronized偏向锁的核心原理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • java封装全局异常处理深入详解

    java封装全局异常处理深入详解

    这篇文章主要为大家介绍了java封装全局异常处理的深入详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • java JVM方法分派模型静态分派动态分派全面讲解

    java JVM方法分派模型静态分派动态分派全面讲解

    这篇文章主要为大家介绍了java JVM方法分派模型静态分派动态分派全面讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • springboot配置templates直接访问的实现

    springboot配置templates直接访问的实现

    这篇文章主要介绍了springboot配置templates直接访问的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • SpringBoot自定义定时任务的实现示例

    SpringBoot自定义定时任务的实现示例

    本文主要介绍了SpringBoot自定义定时任务,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • 前后端分离跨域springBoot跨域有效解决问题

    前后端分离跨域springBoot跨域有效解决问题

    这篇文章主要介绍了前后端分离跨域springBoot跨域有效解决问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 详解Java数组扩容缩容与拷贝的实现和原理

    详解Java数组扩容缩容与拷贝的实现和原理

    这篇文章主要带大家学习数组的扩容、缩容及拷贝,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Spring Boot conditional注解用法详解

    Spring Boot conditional注解用法详解

    这篇文章主要介绍了Spring Boot conditional注解用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论