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 的作用域(如 singleton、prototype),并将其设置到 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直接标记。 - 其他限定符(如自定义注解)会添加到
BeanDefinition的qualifiers列表中。
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 判断条件是否满足 |
@Scope | scope | 解析作用域名称,处理代理模式(proxyMode) |
@Lazy | lazyInit | 设置懒加载为 true |
@Primary | primary | 标记为首选 Bean。 |
@DependsOn | dependsOn | 设置依赖的 Bean 名称列表。 |
@Role | role | 设置 Bean 的角色(ROLE_APPLICATION、ROLE_SUPPORT 等) |
@Description | description | 设置 Bean 的描述信息。 |
示例:转换过程演示
假设有一个类 MyService,其定义如下:
@Lazy
@Primary
@Scope("prototype")
@Conditional(MyCondition.class)
public class MyService {
// ...
}
转换后的 BeanDefinition 属性:
lazyInit = trueprimary = truescope = "prototype"- 如果
MyCondition条件满足,才会注册到容器中。
关键设计思想
- 元数据驱动:通过注解的元数据(
AnnotationMetadata)驱动 Bean 的注册逻辑,而非硬编码配置。 - 职责分离:
-
AnnotatedBeanDefinitionReader负责协调整个流程。ConditionEvaluator、ScopeMetadataResolver等工具类负责具体逻辑。
- 可扩展性:
-
- 可以通过自定义
BeanNameGenerator、ScopeMetadataResolver等组件扩展功能。 - 支持自定义条件注解(实现
Condition接口)。
- 可以通过自定义
实际应用场景
- 显式注册配置类:
在AnnotationConfigApplicationContext中,通过register(MyConfig.class)注册@Configuration类。 - 动态注册 Bean:
在运行时根据条件动态决定是否注册某个 Bean。 - 自定义注解扩展:
结合自定义注解和AnnotatedBeanDefinitionReader,实现特定框架的 Bean 注册逻辑(如 Spring Boot 的@EnableAutoConfiguration)。
通过理解这一过程,可以更灵活地使用 Spring 的注解驱动开发模式,并在需要时进行扩展或调试。