开发者

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

开发者 https://www.devze.com 2025-09-15 10:41 出处:网络 作者: 许苑向上
目录1. 整体流程概览2. 详细步骤解析2.1 扫描阶段:识别候选配置类2.2 解析阶段:处理注解元数据(1) 解析@ComponentScan(2) 解析@Bean方法(3) 解析@Import(4) 处理父类与接口2.3 注册阶段:加载BeanDefinition(1) 注
目录
  • 1. 整体流程概览
  • 2. 详细步骤解析
    • 2.1 扫描阶段:识别候选配置类
    • 2.2 解析阶段:处理注解元数据
      • (1) 解析@ComponentScan
      • (2) 解析@Bean方法
      • (3) 解析@Import
      • (4) 处理父类与接口
    • 2.3 注册阶段:加载BeanDefinition
      • (1) 注册@Import的类
      • (2) 注册@Bean方法
      • (3) 处理嵌套配置类
  • 3. 关键设计点
    • (1) 延迟加载与递归处理
      • (2) 元数据存储
        • (3) 性能优化
        • 4. 示hvrLrBFI例全流程
          • 场景
            • 步骤
            • 5. 总结

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

              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, beanNpythoname));
                  }
                  
                • 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,javascript 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) 处理父类与接口

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

              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. 扫描:通过 BeanDefin编程客栈itionRegistry 筛选候选类。
              2. 解析ConfigurationClassParser 解析注解并生成中间结果(ConfigurationClass)。
              3. 注册ConfigurationClassBeanDefinitionReader 将解析结果转换为 BeanDefinition

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

              到此这篇关于Spring Boot 的注解生效详细步骤解析的文章就介绍到这了,更多相关Spring Boot 注解生效内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

              0

              精彩评论

              暂无评论...
              验证码 换一张
              取 消

              关注公众号