自定义注解实现自动化装配的核心是通过@Import配合ImportBeanDefinitionRegistrar在Spring启动时按需注册Bean;需用@Target、@Retention、@Documented定义注解,并结合@Conditional等条件注解实现智能装配。

自定义注解实现自动化装配,核心是让 Spring 在启动时识别你的注解,并按需注册 Bean。它不是替代 @Autowired,而是扩展自动配置能力——比如标记某类为“可被自动装配的配置提供者”,或触发特定 Bean 的条件注册。
定义自定义注解
用 @Target、@Retention 和 @Documented 声明注解语义,通常搭配 @Import 实现注册逻辑:
- @Target(ElementType.TYPE):限定只能标注在类上
- @Retention(RetentionPolicy.RUNTIME):确保运行期可通过反射读取
- @Documented:支持 Javadoc 生成
-
@Import(ConfigClassRegistrar.class):关键一步,把注册逻辑委托给一个
ImportBeanDefinitionRegistrar实现类
示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigClassRegistrar.class)
public @interface ConfigClass {
String value() default "";
}
实现 ImportBeanDefinitionRegistrar
这个接口让你完全控制 BeanDefinition 的注册过程。Spring 启动扫描到 @ConfigClass 注解后,会调用它的 registerBeanDefinitions 方法:
- 通过
metadata获取被标注类的信息(如类名、是否含特定方法) - 用
registry.registerBeanDefinition()手动注册 Bean,可设置作用域、初始化方法等 - 支持结合
@ConditionalOnMissingBean等条件判断,避免重复注册
例如:自动将标注了 @ConfigClass 的类注册为单例 Bean,并为其注入 Environment:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class ConfigClassRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
String className = metadata.getClassName();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ClassUtils.resolveClassName(className, null));
builder.setScope(BeanDefinition.SCOPE_SINGLETON);
builder.addDependsOn("environment"); // 显式依赖
registry.registerBeanDefinition(className, builder.getBeanDefinition());
}
}
配合条件注解增强智能性
仅靠 @Import 是无条件注册的。要实现“按需装配”,需在被标注类上叠加 Spring Boot 的条件注解:
-
@ConditionalOnClass(DataSource.class):只有项目引入了数据库驱动才生效 -
@ConditionalOnProperty(name = "my.feature.enabled", havingValue = "true"):由配置开关控制 -
@ConditionalOnMissingBean(MyService.class):避免与用户自定义 Bean 冲突
注意:这些注解必须加在被 @ConfigClass 标注的类上,Spring 的条件评估机制才会在注册前检查它们。
在启动类或配置类上启用扫描
Spring 默认只扫描启动类所在包及其子包。若自定义注解和目标配置类不在同一路径下,需显式指定:
- 用
@ComponentScan(basePackages = "com.example.config")扩展扫描范围 - 或直接在启动类上使用
@ConfigClass标注一个配置类(前提是该类已位于扫描路径内)
不需要额外开启任何开关,只要注解本身带 @Import,且被 Spring 扫描到,注册逻辑就会执行。

















