Skip to content

Spring @Bean 注解详解:Java 配置的核心工具 ☕

什么是 @Bean 注解?

@Bean 注解是 Spring Framework 中用于 Java 配置的核心注解,它是 XML 配置中 <bean/> 元素的直接替代品。通过 @Bean 注解,我们可以在 Java 类中声明和配置 Spring 容器中的 Bean。

IMPORTANT

@Bean 注解只能用在被 @Configuration@Component 注解标记的类中的方法上。它告诉 Spring 容器:"这个方法返回的对象应该被注册为一个 Bean"。

为什么需要 @Bean 注解?

在传统的 XML 配置时代,我们需要编写大量的 XML 文件来配置 Bean:

xml
<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
    <bean id="accountRepository" class="com.acme.JdbcAccountRepository"/>
</beans>
kotlin
@Configuration
class AppConfig {
    
    @Bean
    fun transferService(): TransferService {
        return TransferServiceImpl()
    }
    
    @Bean
    fun accountRepository(): AccountRepository {
        return JdbcAccountRepository()
    }
}

TIP

Java 配置相比 XML 配置的优势:

  • 类型安全:编译时就能发现错误
  • IDE 支持:更好的代码补全和重构支持
  • 调试友好:可以在配置代码中设置断点
  • 更灵活:可以使用 Java 的所有语言特性

@Bean 注解的核心功能

1. 声明 Bean

最基本的用法是在方法上添加 @Bean 注解来声明一个 Bean:

kotlin
@Configuration
class AppConfig {
    
    @Bean
    fun transferService(): TransferService { 
        return TransferServiceImpl() // 返回具体实现
    }
}

NOTE

默认情况下,Bean 的名称就是方法名。上面的例子中,Bean 的名称是 transferService

2. Bean 依赖注入

@Bean 方法可以接受参数来声明依赖关系,Spring 会自动注入这些依赖:

kotlin
@Configuration
class AppConfig {
    
    @Bean
    fun accountRepository(): AccountRepository {
        return JdbcAccountRepository()
    }
    
    @Bean
    fun transferService(accountRepository: AccountRepository): TransferService { 
        // Spring 会自动注入 accountRepository 参数
        return TransferServiceImpl(accountRepository)
    }
}

3. 生命周期回调

@Bean 支持指定初始化和销毁回调方法:

kotlin
class DatabaseService {
    fun initialize() {
        println("数据库连接初始化...")
        // 初始化逻辑
    }
    
    fun cleanup() {
        println("清理数据库连接...")
        // 清理逻辑
    }
}

@Configuration
class AppConfig {
    
    @Bean(initMethod = "initialize", destroyMethod = "cleanup") 
    fun databaseService(): DatabaseService {
        return DatabaseService()
    }
}

WARNING

对于具有 close()shutdown() 方法的类(如 DataSource),Spring 会自动推断销毁方法。如果不希望自动调用,需要显式设置 destroyMethod = ""

自动销毁方法的处理示例
kotlin
@Configuration
class DataSourceConfig {
    
    @Bean(destroyMethod = "") 
    fun dataSource(): DataSource {
        // 对于 JNDI 资源,不希望 Spring 管理其生命周期
        return jndiTemplate.lookup("MyDS") as DataSource
    }
}

4. Bean 作用域

使用 @Scope 注解可以指定 Bean 的作用域:

kotlin
@Configuration
class AppConfig {
    
    @Bean
    @Scope("singleton") 
    fun singletonService(): MyService {
        return MyService()
    }
    
    @Bean
    @Scope("prototype") 
    fun prototypeService(): MyService {
        return MyService()
    }
}

NOTE

Spring 支持的主要作用域:

  • singleton(默认):整个应用中只有一个实例
  • prototype:每次请求都创建新实例
  • request:Web 应用中每个 HTTP 请求一个实例
  • session:Web 应用中每个 HTTP 会话一个实例

5. 自定义 Bean 名称和别名

kotlin
@Configuration
class AppConfig {
    
    @Bean("customName") 
    fun someService(): MyService {
        return MyService()
    }
    
    @Bean("dataSource", "primaryDS", "mainDataSource") 
    fun dataSource(): DataSource {
        // 一个 Bean 可以有多个名称(别名)
        return HikariDataSource()
    }
}

实际业务场景示例

让我们通过一个完整的电商订单服务示例来看看 @Bean 的实际应用:

kotlin
// 业务接口定义
interface OrderService {
    fun createOrder(userId: String, productId: String): Order
}

interface PaymentService {
    fun processPayment(orderId: String, amount: BigDecimal): PaymentResult
}

interface NotificationService {
    fun sendOrderConfirmation(order: Order)
}

// 具体实现
class OrderServiceImpl(
    private val paymentService: PaymentService,
    private val notificationService: NotificationService
) : OrderService {
    
    override fun createOrder(userId: String, productId: String): Order {
        val order = Order(userId, productId)
        
        // 处理支付
        val paymentResult = paymentService.processPayment(order.id, order.amount)
        
        if (paymentResult.isSuccess) {
            // 发送通知
            notificationService.sendOrderConfirmation(order)
        }
        
        return order
    }
}

// 配置类
@Configuration
class OrderConfig {
    
    @Bean
    fun paymentService(): PaymentService { 
        return AlipayService() // 使用支付宝支付
    }
    
    @Bean
    fun notificationService(): NotificationService { 
        return EmailNotificationService() // 使用邮件通知
    }
    
    @Bean
    fun orderService( 
        paymentService: PaymentService, // 自动注入
        notificationService: NotificationService // 自动注入
    ): OrderService {
        return OrderServiceImpl(paymentService, notificationService)
    }
}

配置的灵活性

通过 Java 配置,我们可以轻松地切换不同的实现。比如,如果要从支付宝切换到微信支付,只需要修改 paymentService() 方法的返回值即可,而不需要修改业务逻辑代码。

高级特性

1. 条件化 Bean 创建

结合 @Conditional 注解,可以根据条件创建 Bean:

kotlin
@Configuration
class ConditionalConfig {
    
    @Bean
    @ConditionalOnProperty(name = "payment.provider", havingValue = "alipay")
    fun alipayService(): PaymentService { 
        return AlipayService()
    }
    
    @Bean
    @ConditionalOnProperty(name = "payment.provider", havingValue = "wechat")
    fun wechatPayService(): PaymentService { 
        return WechatPayService()
    }
}

2. Profile 特定的 Bean

kotlin
@Configuration
class ProfileConfig {
    
    @Bean
    @Profile("development") 
    fun devDataSource(): DataSource {
        return H2DataSource() // 开发环境使用 H2 数据库
    }
    
    @Bean
    @Profile("production") 
    fun prodDataSource(): DataSource {
        return MySQLDataSource() // 生产环境使用 MySQL
    }
}

最佳实践 ⭐

推荐做法

  1. 返回接口类型@Bean 方法尽量返回接口类型而不是具体实现类型
  2. 合理分组:将相关的 Bean 配置放在同一个 @Configuration 类中
  3. 明确依赖:通过方法参数明确声明 Bean 之间的依赖关系
  4. 适当注释:为复杂的 Bean 配置添加 @Description 注解
kotlin
@Configuration
class ServiceConfig {
    
    @Bean
    @Description("主要的订单处理服务") 
    fun orderService(
        paymentService: PaymentService,
        inventoryService: InventoryService
    ): OrderService { // 返回接口类型
        return OrderServiceImpl(paymentService, inventoryService)
    }
}

注意事项

  • 避免在 @Bean 方法中直接调用其他 @Bean 方法,这可能导致意外的行为
  • 对于单例 Bean,要注意线程安全问题
  • 合理使用作用域,避免内存泄漏

总结

@Bean 注解是 Spring Java 配置的核心,它提供了一种类型安全、灵活且强大的方式来配置应用程序中的 Bean。通过掌握 @Bean 的各种用法,我们可以:

  • ✅ 摆脱繁琐的 XML 配置
  • ✅ 享受类型安全和 IDE 支持
  • ✅ 灵活控制 Bean 的创建和生命周期
  • ✅ 轻松实现依赖注入和管理

掌握了 @Bean 注解,你就掌握了现代 Spring 应用配置的精髓! 🎉