SpringBoot自定义注解+启动自动注册Bean完整实现
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
一、核心实现原理
SpringBoot启动时会加载BeanDefinition并实例化Bean,借助Spring提供的ImportBeanDefinitionRegistrar扩展接口,可在Bean定义注册阶段,扫描带有自定义注解的类,手动将其注册为Spring Bean,全程无侵入、贴合Spring原生生命周期。
核心关键点:自定义标记注解 + 注解扫描注册器 + 启动启用配置,三步完成自动注册
二、完整代码实现
2.1 自定义标记注解(AutoRegisterBean)
创建自定义注解,用于标记需要自动注册为Bean的类,支持指定Bean名称、作用域等属性。
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* 自定义注解:标记类在SpringBoot启动时自动注册为Bean
* 继承@Component元注解,兼容Spring原生Bean管理机制
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface AutoRegisterBean {
/**
* Bean名称,等价于@Component的value属性
*/
@AliasFor(annotation = Component.class)
String value() default "";
/**
* Bean作用域:单例/多例
*/
String scope() default "singleton";
/**
* 是否懒加载
*/
boolean lazyInit() default false;
}
2.2 实现Bean注册器(AutoBeanDefinitionRegistrar)
实现ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions方法,扫描自定义注解并注册BeanDefinition。
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ClassUtils;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
/**
* 自定义Bean注册器:扫描@AutoRegisterBean注解,启动时自动注册Bean
*/
public class AutoBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 注册Bean定义的核心方法
* @param importingClassMetadata 导入类的元数据
* @param registry Bean定义注册器
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
try {
// 1. 获取当前项目的基础包路径(启动类所在包)
String basePackage = ClassUtils.getPackageName(importingClassMetadata.getClassName());
// 2. 构建注解扫描器,仅扫描@AutoRegisterBean标记的类
MetadataReaderFactory metadataReaderFactory = (MetadataReaderFactory) ClassUtils.forName(
"org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider$DefaultMetadataReaderFactory",
this.getClass().getClassLoader()
).newInstance();
// 3. 遍历基础包下所有类,筛选注解标记类
Set<MetadataReader> metadataReaders = new org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider(false)
.addIncludeFilter(new AnnotationTypeFilter(AutoRegisterBean.class))
.findCandidateComponents(basePackage);
// 4. 遍历筛选结果,手动注册Bean
for (MetadataReader reader : metadataReaders) {
AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
// 获取类全限定名
String className = annotationMetadata.getClassName();
// 获取自定义注解属性
Map<String, Object> annotationAttrs = annotationMetadata.getAnnotationAttributes(AutoRegisterBean.class.getName());
// 构建BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(className);
// 设置作用域
builder.setScope((String) annotationAttrs.get("scope"));
// 设置懒加载
builder.setLazyInit((boolean) annotationAttrs.get("lazyInit"));
BeanDefinition beanDefinition = builder.getBeanDefinition();
// 获取Bean名称(优先取注解value,无则取类名首字母小写)
String beanName = (String) annotationAttrs.get("value");
if (beanName.isEmpty()) {
beanName = ClassUtils.getShortNameAsProperty(className);
}
// 注册BeanDefinition
if (!registry.containsBeanDefinition(beanName)) {
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
} catch (Exception e) {
throw new RuntimeException("自定义注解Bean注册失败", e);
}
}
}
2.3 自定义启用注解(EnableAutoRegisterBean)
创建启用注解,通过@Import导入注册器,实现一键启用自动注册功能。
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 启用注解:开启自定义Bean自动注册功能
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AutoBeanDefinitionRegistrar.class)
public @interface EnableAutoRegisterBean {
}
2.4 SpringBoot启动类配置
在启动类添加@EnableAutoRegisterBean注解,启用自动注册功能。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot启动类
*/
@SpringBootApplication
@EnableAutoRegisterBean // 开启自定义Bean自动注册
public class CustomAnnotationApplication {
public static void main(String[] args) {
SpringApplication.run(CustomAnnotationApplication.class, args);
}
}
2.5 测试Bean(标记自定义注解)
创建业务类,标记@AutoRegisterBean注解,启动时自动注册为Bean。
import lombok.extern.slf4j.Slf4j;
import javax.annotation.PostConstruct;
/**
* 测试Bean:通过自定义注解自动注册
*/
@Slf4j
@AutoRegisterBean(value = "customTestBean", scope = "singleton", lazyInit = false)
public class CustomTestBean {
/**
* Bean初始化后执行,验证注册成功
*/
@PostConstruct
public void init() {
log.info("===== 自定义注解Bean注册成功,Bean名称:customTestBean =====");
}
public void testMethod() {
log.info("自定义注册Bean的方法执行成功");
}
}
2.6 验证注册结果
编写测试类,从Spring容器获取Bean并调用方法,验证注册生效。
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CustomBeanTest {
// 注入自动注册的Bean
@Autowired
private CustomTestBean customTestBean;
@Test
public void testCustomBean() {
// 调用Bean方法,验证注册成功
customTestBean.testMethod();
}
}
三、关键扩展与优化
- 多包扫描适配:修改注册器逻辑,支持指定扫描包路径,避免仅扫描启动类包
- 条件注册:结合@Conditional注解,实现按环境、配置动态注册Bean
- Bean初始化回调:支持自定义初始化、销毁方法,贴合Spring生命周期
- 排除规则:添加exclude属性,排除指定类不注册为Bean
四、核心注意事项
1. 注册器需实现ImportBeanDefinitionRegistrar,不可直接用@Component,否则无法参与BeanDefinition注册阶段
2. 自定义注解继承@Component,可兼容Spring依赖注入、AOP等原生特性
3. 避免重复注册:注册前判断registry是否包含BeanDefinition,防止Bean名称冲突
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
本专栏聚焦Spring全生态体系,从IoC/AOP核心原理入手,覆盖Spring Boot自动配置、事务管理、Web开发等实战内容。拆解循环依赖、动态代理等高频面试难点,助力开发者从入门到精通,打通单体到微服务的技术链路,解决企业级开发痛点,提升架构设计与问题排查能力,成为Java后端进阶的必备技术专栏。
