AnnotatedBeanDefinitionReader 如何将带有注解的类转换为 BeanDefinition

67 阅读3分钟

AnnotatedBeanDefinitionReader 将带有注解的类转换为 BeanDefinition 的过程可以分为以下几个关键步骤,每个步骤都涉及对注解的解析和元数据的处理:


1. 创建 AnnotatedGenericBeanDefinition

当调用 register(Class<?>... annotatedClasses) 方法时,每个传入的类会被包装成一个 AnnotatedGenericBeanDefinition 对象。
关键操作

  • 通过类的 AnnotationMetadata(注解元数据)获取所有类级别的注解信息。
  • AnnotationMetadata 的生成方式:
    • 如果是通过反射加载的类,直接解析类上的注解。
    • 如果是未加载的类(如通过字节码扫描),使用 ASM 库读取类文件,避免触发类的初始化。
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

2. 处理条件注解( @Conditional

检查类是否满足 @Conditional 注解定义的条件,如果不满足则跳过注册。
关键操作

  • 使用 ConditionEvaluator 判断是否应跳过当前 Bean 的注册。
  • ConditionEvaluator 会解析 @Conditional 注解中的条件类,并调用其 matches 方法。
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    return; // 条件不满足,直接跳过
}

3. 解析作用域( @Scope

确定 Bean 的作用域(如 singletonprototype),并将其设置到 BeanDefinition 中。
关键操作

  • 默认作用域是 singleton
  • 使用 ScopeMetadataResolver(默认实现是 AnnotationScopeMetadataResolver)解析 @Scope 注解。
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());

4. 处理通用注解( @Lazy @Primary @DependsOn 等)

解析类上的通用注解,并将信息写入 BeanDefinition
关键操作

  • 调用 AnnotationConfigUtils.processCommonDefinitionAnnotations() 方法,处理以下注解:
    • @Lazy:设置懒加载(setLazyInit)。
    • @Primary:标记为首选 Bean(setPrimary)。
    • @DependsOn:设置依赖的 Bean(setDependsOn)。
    • @Role:设置 Bean 的角色(如框架内部使用或用户定义)。
    • @Description:设置 Bean 的描述信息。
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

5. 生成 Bean 名称

如果没有显式指定 Bean 名称,则通过 BeanNameGenerator 生成默认名称。
关键操作

  • 默认使用 AnnotationBeanNameGenerator,生成规则为类名的首字母小写形式(如 userService)。
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

6. 处理限定符( @Qualifier 或自定义注解)

如果传入了额外的限定符注解(如 @Qualifier),将其添加到 BeanDefinition 中。
关键操作

  • 支持通过 @Primary@Lazy 直接标记。
  • 其他限定符(如自定义注解)会添加到 BeanDefinitionqualifiers 列表中。
if (qualifiers != null) {
    for (Class<? extends Annotation> qualifier : qualifiers) {
        if (Primary.class == qualifier) {
            abd.setPrimary(true);
        } else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
        } else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
        }
    }
}

7. 处理作用域代理(Scoped Proxy)

如果作用域需要代理(如 @Scope(proxyMode = ...)),创建代理对象并包装 BeanDefinition
关键操作

  • 使用 ScopedProxyUtils.createScopedProxy() 生成代理的 BeanDefinition
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

8. 注册 BeanDefinition

将最终的 BeanDefinition 注册到 BeanDefinitionRegistry(通常是 DefaultListableBeanFactory)。
关键操作

  • 调用 BeanDefinitionReaderUtils.registerBeanDefinition() 完成注册。
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

总结:注解到 BeanDefinition 的映射**

注解BeanDefinition属性处理逻辑
@Conditional是否跳过注册通过 ConditionEvaluator 判断条件是否满足
@Scopescope解析作用域名称,处理代理模式(proxyMode
@LazylazyInit设置懒加载为 true
@Primaryprimary标记为首选 Bean。
@DependsOndependsOn设置依赖的 Bean 名称列表。
@Rolerole设置 Bean 的角色(ROLE_APPLICATIONROLE_SUPPORT 等)
@Descriptiondescription设置 Bean 的描述信息。

示例:转换过程演示

假设有一个类 MyService,其定义如下:

@Lazy
@Primary
@Scope("prototype")
@Conditional(MyCondition.class)
public class MyService {
    // ...
}

转换后的 BeanDefinition 属性

  • lazyInit = true
  • primary = true
  • scope = "prototype"
  • 如果 MyCondition 条件满足,才会注册到容器中。

关键设计思想

  1. 元数据驱动:通过注解的元数据(AnnotationMetadata)驱动 Bean 的注册逻辑,而非硬编码配置。
  2. 职责分离
    • AnnotatedBeanDefinitionReader 负责协调整个流程。
    • ConditionEvaluatorScopeMetadataResolver 等工具类负责具体逻辑。
  1. 可扩展性
    • 可以通过自定义 BeanNameGeneratorScopeMetadataResolver 等组件扩展功能。
    • 支持自定义条件注解(实现 Condition 接口)。

实际应用场景

  1. 显式注册配置类
    AnnotationConfigApplicationContext 中,通过 register(MyConfig.class) 注册 @Configuration 类。
  2. 动态注册 Bean
    在运行时根据条件动态决定是否注册某个 Bean。
  3. 自定义注解扩展
    结合自定义注解和 AnnotatedBeanDefinitionReader,实现特定框架的 Bean 注册逻辑(如 Spring Boot 的 @EnableAutoConfiguration)。

通过理解这一过程,可以更灵活地使用 Spring 的注解驱动开发模式,并在需要时进行扩展或调试。