Spring Boot框架,类注入成 Bean的方式

在 Spring Boot 中,将一个类注入成 Bean(即交由 Spring 容器管理)主要有以下几种方式:

方式 适用场景 优点 缺点
@Component 系列 自己写的类 简单快捷 侵入性强
@Bean 第三方类、配置类 灵活、无侵入 需要配置类
@Import 动态导入、模块化 批量导入方便 理解成本稍高
FactoryBean 复杂创建逻辑 高度定制 代码较多
@Conditional 条件注册 灵活控制 增加复杂度

1. @Component 系列注解

最常用的方式,在类上直接添加注解。

java 复制代码
// @Component 通用注解
@Component
public class UserService {
    public void doSomething() {
        System.out.println("UserService doing something");
    }
}

// @Service 业务层专用
@Service
public class OrderService {
    public void createOrder() {
        System.out.println("Order created");
    }
}

// @Repository 数据访问层专用
@Repository
public class UserRepository {
    public void save() {
        System.out.println("User saved");
    }
}

// @Controller / @RestController Web层专用
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello";
    }
}

2. @Bean 配合 @Configuration

适用于第三方类或需要自定义初始化逻辑的 Bean。

java 复制代码
@Configuration
public class AppConfig {
    
    // 注册第三方类
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    // 带初始化/销毁方法的 Bean
    @Bean(initMethod = "init", destroyMethod = "cleanup")
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
    
    // 依赖其他 Bean
    @Bean
    public UserService userService(OrderService orderService) {
        return new UserService(orderService);
    }
}

3. @Import 注解

导入特定类作为 Bean,适用于无法修改源码的类。

java 复制代码
// 方式1:直接导入类
@Import({ExternalService.class, HelperUtil.class})
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 方式2:导入 ImportSelector
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"com.example.ServiceA", "com.example.ServiceB"};
    }
}

@Import(MyImportSelector.class)
@SpringBootApplication
public class Application { }

// 方式3:导入 ImportBeanDefinitionRegistrar(更灵活的注册)
public class MyBeanRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, 
                                       BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder
            .genericBeanDefinition(UserService.class)
            .addPropertyValue("name", "test");
        registry.registerBeanDefinition("userService", builder.getBeanDefinition());
    }
}

4. FactoryBean 接口

用于创建复杂对象的 Bean。

java 复制代码
@Component
public class MyBeanFactory implements FactoryBean<UserService> {
    
    @Override
    public UserService getObject() throws Exception {
        // 复杂的创建逻辑
        UserService userService = new UserService();
        userService.setName("Created by FactoryBean");
        return userService;
    }
    
    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true; // 单例模式
    }
}

5. @ComponentScan 自定义扫描路径

指定 Spring 扫描哪些包下的注解类。

java 复制代码
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.service", "com.example.repository"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

6. 实现 InitializingBeanBeanPostProcessor

在 Bean 注册后进行额外处理(较少用于注册本身)。

java 复制代码
@Component
public class CustomBean implements InitializingBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean 初始化完成");
        // 可以在此做额外配置
    }
}

7. 条件化注册 @Conditional

根据条件决定是否注册 Bean。

java 复制代码
@Configuration
public class ConditionalConfig {
    
    @Bean
    @ConditionalOnMissingBean  // 不存在时才创建
    public UserService userService() {
        return new UserService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
    public CacheManager cacheManager() {
        return new RedisCacheManager();
    }
    
    @Bean
    @ConditionalOnClass(name = "com.mysql.jdbc.Driver")
    public DataSource mysqlDataSource() {
        return new MysqlDataSource();
    }
}

实际开发中最常用的是前两种 :自己写的类用 @Service/@Component,第三方类或需要配置的类用 @Bean

相关推荐
Rust研习社3 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒4 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro5 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax5 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH5 小时前
Koa和Express的区别
后端
MariaH5 小时前
Koa框架的使用
后端
luckdewei6 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某8 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy8 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom8 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github