前言
在Spring Boot应用中,Bean是构成应用的核心组件。Spring容器负责管理这些Bean,包括它们的创建、配置、组装、管理和销毁。在Spring Boot中,有多种方式可以注册Bean,让Spring容器能够管理它们。
一、@Component及其派生注解
实现方式
- @Component是一个泛化的注解,用于标记一个类作为Spring容器管理的Bean。
- 在类上添加@Component、@Service、@Controller、@Repository等注解,配合@ComponentScan扫描包路径。
适用场景
- 常规业务组件(如Service层、Controller层等)
- 需要Spring自动扫描并管理的类
@Service
public class MyService {
// 服务逻辑...
}
二、@Bean注解
实现方式
- 在配置类(@Configuration标记的类)中,通过@Bean标注方法,返回对象实例。方法名默认为Bean的唯一标识。
适用场景
- 引入第三方库的类(如数据库连接池、工具类)
- 需要自定义初始化逻辑的Bean
@Configuration
public class MyConfig {
@Bean
public User user() {
return new User("Marry", 12345L);
}
}
三、@Import注解导入
3.1、导入其他配置类或普通类
实现方式
- 在配置类中使用@Import导入其他配置类或普通类,使其成为Bean。
适用场景
- 模块化配置(如将多个配置类分散管理,根据需要组合它们)
- 快速注册单个Bean,,等同于在类上标注@Component
// 安全模块配置
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilter securityFilter() {
return new SecurityFilter();
}
}
// 数据访问模块配置
@Configuration
public class DataAccessConfig {
@Bean
public Repository repository() {
return new JpaRepository();
}
}
// 无特殊注解
public class BeanD {
}
// 主配置类
@Configuration
@Import({SecurityConfig.class, DataAccessConfig.class, BeanD.class})
public class ApplicationConfig {
@Bean
public MyService myService() {
// 可以使用DataAccessConfig中的bean
return new MyService(repository());
}
}
3.2、使用ImportSelector进行动态导入
实现方式
- 需创建实现ImportSelector接口的类,并重写selectImports()方法返回需注册的类全限定名数组。
适用场景
- 结合@Conditional等注解,可在selectImports()中根据条件(如配置属性、环境变量)动态返回不同的类名数组,实现按需加载。
- 如SpringBoot的@EnableAutoConfiguration通过AutoConfigurationImportSelector加载spring.factories中的自动配置类
- AnnotationMetadata参数可获取导入类的注解、接口、父类等信息(如@EnableXXX的配置),用于更复杂的逻辑判断
- 如下则是判断MyCofig类上有@Configuration注解则加载Dog类,否则加载Cat类
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
System.out.println("元数据Class名称:" + metadata.getClassName());
//各种条件的判定,判定完毕后,决定是否装载指定的bean
boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Configuration");
if(flag){
return new String[]{"com.xc.springboot.bean.Dog"};
}
return new String[]{"com.xc.springboot.bean.Cat"};
}
}
// 使用方式
@Configuration
@Import(MyImportSelector.class)
public class MyConfig {
}
3.3、使用ImportBeanDefinitionRegistrar进行更灵活的控制
实现方式
- 需创建实现ImportBeanDefinitionRegistrar接口的类,并重写registerBeanDefinitions()方法通过BeanDefinitionRegistry动态注册Bean。
适用场景
- 根据环境变量、类路径是否存在类等条件动态注册Bean
- 如MyBatisMapper扫描等,利用该机制动态生成代理类
- 通过@EnableMyFeature注解触发ImportBeanDefinitionRegistrar实现类,根据环境变量条件动态注册MyServiceImpl的Bean到Spring容器,实现灵活的编程式配置。
// 1.自定义注解@EnableMyFeature
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyFeatureRegistrar.class) // 关联注册实现类
public @interface EnableMyFeature {
String value() default "";
}
// 2.实现ImportBeanDefinitionRegistrar
public class MyFeatureRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 读取@EnableMyFeature注解的属性
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableMyFeature.class.getName());
String value = (String) attrs.get("value");
// 示例:根据环境变量决定是否注册Bean
boolean isEnabled = environment.getProperty("my.feature.enabled", Boolean.class, false);
if (isEnabled) {
BeanDefinition beanDef = BeanDefinitionBuilder
.genericBeanDefinition(MyServiceImpl.class)
.addPropertyReference("dependency", "myDependency")
.getBeanDefinition();
registry.registerBeanDefinition("myService", beanDef);
}
}
}
// 3.在配置类中使用@EnableMyFeature
@Configuration
@EnableMyFeature("customValue") // 触发MyFeatureRegistrar的执行
public class AppConfig {
// 其他Bean定义...
}
3.4、ImportSelector 与 ImportBeanDefinitionRegistrar区别

image.png
四、FactoryBean接口实现
实现方式
- 实现FactoryBean接口,重写getObject()方法定义Bean实例,并通过@Component或@Bean注册接口实现类。
适用场景
- 复杂对象的创建(如MyBatis的SqlSessionFactoryBean)
- 需要延迟初始化或条件创建的Bean
- 容器中实际注册的是getObject()返回的对象,而非FactoryBean本身
@Component
public class DogFactoryBean implements FactoryBean<Dog> {
//创建bean的复杂过程
@Override
public Dog getObject() throws Exception {
Dog d = new Dog();
//.........
return d;
}
//bean的类型
@Override
public Class<?> getObjectType() {
return Dog.class;
}
//bean是否单例
@Override
public boolean isSingleton() {
return true;
}
}
五、编程式注册(ApplicationContext)
实现方式
- 通过ApplicationContext或BeanFactory直接注册Bean。
适用场景
- 在运行时动态添加Bean
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args)
.getBeanFactory()
.registerSingleton("customBean", new CustomBean());
}
}
六、@ComponentScan注解
实现方式
- @ComponentScan注解用于指定Spring Boot启动时扫描的包路径。Spring容器会扫描这些包路径下的类,并将标记了@Component、@Service、@Repository、@Controller等注解的类注册为Bean。
适用场景
- 当你需要让Spring Boot在启动时扫描特定的包路径,并注册其中的Bean时,可以使用@ComponentScan注解。
// 定义一个Service类,并使用@Service注解标记
@Service
public class MyService {
// 服务逻辑...
}
// 在主配置类中使用@ComponentScan注解指定扫描的包路径
@Configuration
@ComponentScan(basePackages = "com.example.myapp")
public class AppConfig {
// 其他Bean定义...
}
七、自动配置(Spring Boot Starter)
实现方式
- 通过/META-INF/spring.factories声明自动配置类,结合@Conditional实现按需装配。
- 通过/META-INF/spring/AutoConfiguration.imports 声明自动配置类,结合@Conditional实现按需装配。
注意:
- springboot2.7版本以前,自动配置使用的配置文件为:META-INF/spring.factories,会从这个文件中读取自动配置类的全类名
- springboot2.7到3.0以前,同时兼容了AutoConfiguration.imports和spring.factories文件
- springboot3.0以后,自动配置只支持AutoConfiguration.imports文件
@AutoConfiguration
- @AutoConfiguration 是 Spring Boot 3 中引入的新注解,是 @Configuration 的增强版,同时支持 @AutoConfigureBefore、@AutoConfigureAfter。
注册自动配置类的文件
- 路径必须是:
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
- 内容示例(每行一个类全限定名)
- 这是 Spring Boot 3 的关键注册方式,相当于新版本的 spring.factories。
适用场景
- 开发自定义Starter
- 封装通用模块供多个项目复用
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xc.MyAutoConfiguration
@Configuration
public class MyAutoConfiguration {
@Bean
public MyBean myBean() { ... }
}
八、@ImportResource注解导入XML配置
实现方式
- 在XML文件中通过<bean>标签定义Bean,并在配置类中使用@ImportResource导入XML文件。
适用场景
- 旧系统迁移或集成遗留XML配置
- 需要与Spring Boot注解配置混合使用
<!-- beans.xml -->
<bean id="xmlUser" class="com.example.User" />
@ImportResource("classpath:beans.xml")
@Configuration
public class XmlConfig { ... }
九、动态注册:BeanDefinitionRegistryPostProcessor
实现方式
- 实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry()方法中手动注册BeanDefinition。
适用场景
- 框架开发中动态注册Bean(如Spring Boot Starter自动配置)
- 根据运行时条件(如配置文件、环境变量)决定是否注册Bean
- 以在Bean实例化前修改容器元信息
@Component
public class DynamicRegistrar implements BeanDefinitionRegistryPostProcessor {
// 注册Bean定义(先执行)
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(User.class)
.addPropertyValue("name", "DynamicUser")
.getBeanDefinition();
registry.registerBeanDefinition("dynamicUser", definition);
}
// 修改Bean定义(后执行-加载所有Bean定义之后、Bean实例化之前)
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 在这里可以对 BeanFactory 进行进一步的配置
System.out.println("Bean factory post-processing");
}
}
十、使用@EnableXxx注解
- Spring Boot提供了许多@Enable*注解,如@EnableWebMvc、@EnableCaching等。这些注解通常会通过导入一个或多个配置类来启用特定的功能,并注册相关的Bean。
// 在配置类上使用@EnableWebMvc注解启用Spring MVC
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
// 配置Spring MVC...
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 注册视图控制器...
}
}
适用场景
- 当你需要使用Spring Boot提供的特定功能,并且这些功能是通过@Enable*注解来启用的时,可以使用这些注解来注册相关的Bean。
自定义一个@EnableMyFeature
- 自定义一个@EnableMyFeature 类似的功能要创建一个注解,并使用@Import注解来导入一个配置类或选择器。这样,当你在应用程序中使用这个自定义的@Enable注解时,Spring会自动导入并注册相关的配置或组件
// 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyEnableConfiguration.class)
public @interface EnableMyFeature {
// 可以添加属性来配置功能
}
// 配置类
@Configuration
public class MyEnableConfiguration {
@Bean
public MyFeatureBean myFeatureBean() {
return new MyFeatureBean();
}
}
// 使用自定义注解
@SpringBootApplication
@EnableMyFeature
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
十一、编程式地注册Bean(使用ApplicationContext)
某些情况下需要在运行时编程式地注册Bean。可以通过获取ApplicationContext的引用,并使用其提供的API来注册Bean。
@Component
public class MyBeanRegistrar implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
registerBean();
}
private void registerBean() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
applicationContext.getBeanFactory().registerSingleton("myBean", beanDefinition);
}
}
适用场景
- 当你需要在运行时动态地注册Bean时,可以使用编程式地注册Bean的方式。这种方式比较罕见,通常只在特定的场景下使用。
参考:
https://cloud.tencent.com/developer/article/2443495