理解 Spring Boot 的 Bean 加载原理后,更重要的是在实际开发中正确使用。本文从用户角度出发,总结 Bean 的使用规范和最佳实践。

1. Bean 定义方式

Spring 提供了多种定义 Bean 的方式,各有适用场景:

// ========== 方式一:@Component 及其派生注解 ==========
// 最常用,适合业务组件
@Component      // 通用组件
@Service        // 业务服务层
@Repository     // 数据访问层
@Controller     // Web 控制器
@RestController // RESTful API 控制器(@Controller + @ResponseBody)
@Configuration  // 配置类

// 示例
@Service
public class UserServiceImpl implements UserService {
    // 业务逻辑
}

// ========== 方式二:@Configuration + @Bean ==========
// 适合第三方库组件、需要复杂初始化逻辑的 Bean
@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            .connectTimeout(Duration.ofSeconds(5))
            .readTimeout(Duration.ofSeconds(10))
            .build();
    }
}

// ========== 方式三:@Import 直接导入 ==========
// 适合需要强制加载的配置类
@Import({RedisConfig.class, MongoConfig.class})
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// ========== 方式四:ImportSelector / ImportBeanDefinitionRegistrar ==========
// 适合条件化加载大量 Bean(框架开发者常用)
public class MyAutoConfigurationImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"com.example.MyConfiguration"};
    }
}

选择建议:

场景推荐方式
自己的业务类@Service@Repository@Controller
第三方库组件@Configuration + @Bean
需要条件化加载@Configuration + @ConditionalXxx
框架/库开发ImportSelector / ImportBeanDefinitionRegistrar

2. Bean 注入方式

Spring 支持三种注入方式,各有优劣:

// ========== 方式一:构造器注入(推荐)==========
// 优点:不可变、强制依赖、易于测试、避免循环依赖
@Service
public class OrderService {
    private final UserService userService;
    private final OrderRepository orderRepository;
    
    // Spring 4.3+ 单构造器可省略 @Autowired
    public OrderService(UserService userService, OrderRepository orderRepository) {
        this.userService = userService;
        this.orderRepository = orderRepository;
    }
}

// ========== 方式二:Setter 注入 ==========
// 优点:可选依赖、灵活性高
// 缺点:可能导致对象状态不完整
@Service
public class PaymentService {
    private NotificationService notificationService;
    
    @Autowired(required = false)  // 可选依赖
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}

// ========== 方式三:字段注入(不推荐)==========
// 缺点:难以测试、隐藏依赖、无法声明不可变字段
@Service
public class BadService {
    @Autowired
    private UserRepository userRepository;  // 不推荐!
    
    @Autowired
    private EmailService emailService;      // 不推荐!
}

注入方式对比:

特性构造器注入Setter 注入字段注入
不可变性✅ 支持❌ 不支持❌ 不支持
可选依赖❌ 不支持✅ 支持✅ 支持
单元测试✅ 容易 Mock✅ 容易 Mock❌ 需要 Reflection
循环依赖❌ 编译期发现✅ 可规避✅ 可规避
明确依赖✅ 显式声明⚠️ 不够明确❌ 隐藏依赖

最佳实践:

// ✅ 推荐:构造器注入 + final 字段
@Service
public class GoodService {
    private final RequiredDependency required;
    private OptionalDependency optional;
    
    public GoodService(RequiredDependency required) {
        this.required = required;
    }
    
    @Autowired(required = false)
    public void setOptional(OptionalDependency optional) {
        this.optional = optional;
    }
}

3. 接口与基类的 Bean 注入

当注入目标是接口或基类时,Spring 需要确定具体注入哪个实现。这是实际开发中常见且容易混淆的场景。

3.1 接口注入的基本原理

// 接口定义
public interface PaymentService {
    void pay(Order order);
}

// 实现类一
@Service
public class AlipayService implements PaymentService {
    @Override
    public void pay(Order order) {
        // 支付宝支付逻辑
    }
}

// 实现类二
@Service
public class WechatPayService implements PaymentService {
    @Override
    public void pay(Order order) {
        // 微信支付逻辑
    }
}

此时容器中有两个 PaymentService 类型的 Bean:

  • alipayService(类名首字母小写)
  • wechatPayService

3.2 多实现的注入方式

方式一:按名称注入(@Qualifier)

@Service
public class OrderService {
    private final PaymentService paymentService;
    
    // 明确指定 Bean 名称
    public OrderService(@Qualifier("alipayService") PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

方式二:字段名匹配

@Service
public class OrderService {
    // 字段名与 Bean 名称一致,自动匹配
    private final PaymentService alipayService;
    
    public OrderService(PaymentService alipayService) {
        this.alipayService = alipayService;
    }
}

方式三:@Primary 指定默认实现

@Service
@Primary  // 标记为默认实现
public class AlipayService implements PaymentService {
    // ...
}

@Service
public class WechatPayService implements PaymentService {
    // ...
}

// 注入时不指定名称,自动选择 @Primary 标记的 Bean
@Service
public class OrderService {
    private final PaymentService paymentService;  // 注入 AlipayService
    
    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

方式四:注入所有实现(List/Map)

@Service
public class PaymentRouter {
    // 注入所有 PaymentService 实现
    private final List<PaymentService> paymentServices;
    
    // 或者使用 Map,key 为 Bean 名称
    private final Map<String, PaymentService> paymentServiceMap;
    
    public PaymentRouter(List<PaymentService> paymentServices,
                         Map<String, PaymentService> paymentServiceMap) {
        this.paymentServices = paymentServices;
        this.paymentServiceMap = paymentServiceMap;
    }
    
    public void pay(String payType, Order order) {
        // 方式一:遍历 List
        for (PaymentService service : paymentServices) {
            if (service.supports(payType)) {
                service.pay(order);
                return;
            }
        }
        
        // 方式二:从 Map 获取
        PaymentService service = paymentServiceMap.get(payType + "PayService");
        if (service != null) {
            service.pay(order);
        }
    }
}

3.3 抽象类与继承体系

// 抽象基类
public abstract class BaseService<T, ID> {
    protected abstract BaseRepository<T, ID> getRepository();
    
    public Optional<T> findById(ID id) {
        return getRepository().findById(id);
    }
    
    public T save(T entity) {
        return getRepository().save(entity);
    }
}

// 具体实现
@Service
public class UserService extends BaseService<User, Long> {
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    protected BaseRepository<User, Long> getRepository() {
        return userRepository;
    }
}

@Service
public class OrderService extends BaseService<Order, Long> {
    private final OrderRepository orderRepository;
    
    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
    
    @Override
    protected BaseRepository<Order, Long> getRepository() {
        return orderRepository;
    }
}

注入基类类型:

@Service
public class CompositeService {
    // 注入所有 BaseService 实现
    private final List<BaseService<?, ?>> services;
    
    public CompositeService(List<BaseService<?, ?>> services) {
        this.services = services;
    }
}

3.4 泛型接口注入

Spring 4.0+ 支持泛型类型作为限定符:

// 泛型接口
public interface Repository<T> {
    Optional<T> findById(Long id);
    T save(T entity);
}

// 具体实现
@Repository
public class UserRepository implements Repository<User> {
    // ...
}

@Repository
public class OrderRepository implements Repository<Order> {
    // ...
}

// 注入时按泛型类型区分
@Service
public class UserService {
    // Spring 自动匹配 Repository<User> 的实现
    private final Repository<User> userRepository;
    
    public UserService(Repository<User> userRepository) {
        this.userRepository = userRepository;
    }
}

@Service
public class OrderService {
    // Spring 自动匹配 Repository<Order> 的实现
    private final Repository<Order> orderRepository;
    
    public OrderService(Repository<Order> orderRepository) {
        this.orderRepository = orderRepository;
    }
}

3.5 条件化选择实现

结合 @Conditional 实现运行时选择不同实现:

// 配置类
@Configuration
public class PaymentConfig {
    @Bean
    @Primary
    @ConditionalOnProperty(name = "payment.provider", havingValue = "alipay", matchIfMissing = true)
    public PaymentService alipayService() {
        return new AlipayService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "payment.provider", havingValue = "wechat")
    public PaymentService wechatPayService() {
        return new WechatPayService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "payment.provider", havingValue = "unionpay")
    public PaymentService unionPayService() {
        return new UnionPayService();
    }
}

3.6 接口注入决策表

场景推荐方式示例
单实现直接注入接口类型PaymentService service
多实现,有默认@Primary + 接口类型@Primary class AlipayService
多实现,需指定@Qualifier 或字段名匹配@Qualifier("alipayService")
需要所有实现List<Interface>Map<String, Interface>List<PaymentService>
泛型接口按泛型类型注入Repository<User>
运行时选择@Conditional + 配置类@ConditionalOnProperty

4. Bean 作用域

Spring 支持多种 Bean 作用域,默认为单例:

// ========== 单例(默认)==========
// 整个应用只有一个实例
// 适合:无状态服务、工具类、配置类
@Service
@Scope("singleton")  // 可省略,默认就是单例
public class UserService {
    // 无状态,线程安全
}

// ========== 原型(Prototype)==========
// 每次获取都创建新实例
// 适合:有状态对象、需要隔离的场景
@Component
@Scope("prototype")
public class RequestContext {
    private String requestId;
    private Map<String, Object> attributes = new HashMap<>();
}

// ========== Web 作用域 ==========
// Request:每个 HTTP 请求一个实例
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
    private String requestId;
}

// Session:每个 HTTP 会话一个实例
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedBean {
    private User currentUser;
}

// Application:ServletContext 生命周期
@Component
@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
public class ApplicationScopedBean {
    // 效果类似单例,但属于 Web 容器
}

作用域选择原则:

┌─────────────────────────────────────────────────────────────┐
│  Bean 是否有状态?                                            │
│     ├─ 无状态 → singleton(默认)                             │
│     └─ 有状态                                                 │
│          ├─ 状态需要跨请求共享?                               │
│          │    ├─ 是 → session                                 │
│          │    └─ 否                                           │
│          │         ├─ 单请求内有效?→ request                 │
│          │         └─ 每次使用都需要新实例?→ prototype        │
└─────────────────────────────────────────────────────────────┘

5. Bean 生命周期回调

正确使用生命周期回调,可以在合适的时机执行初始化和清理逻辑:

// ========== 方式一:JSR-250 注解(推荐)==========
@Component
public class DatabaseConnectionPool {
    @PostConstruct
    public void init() {
        // 初始化连接池
        System.out.println("连接池初始化完成");
    }
    
    @PreDestroy
    public void destroy() {
        // 关闭连接池
        System.out.println("连接池已关闭");
    }
}

// ========== 方式二:Spring 接口 ==========
@Component
public class CacheManager implements InitializingBean, DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化缓存
    }
    
    @Override
    public void destroy() throws Exception {
        // 清理缓存
    }
}

// ========== 方式三:@Bean 属性 ==========
@Configuration
public class AppConfig {
    @Bean(initMethod = "start", destroyMethod = "stop")
    public CustomService customService() {
        return new CustomService();
    }
}

生命周期回调执行顺序:

Bean 实例化
    ↓
@PostConstruct
    ↓
InitializingBean.afterPropertiesSet()
    ↓
@Bean(initMethod)
    ↓
[Bean 就绪,可正常使用]
    ↓
@PreDestroy
    ↓
DisposableBean.destroy()
    ↓
@Bean(destroyMethod)
    ↓
Bean 销毁

最佳实践:优先使用 @PostConstruct@PreDestroy

6. 条件化 Bean 加载

Spring Boot 提供了丰富的条件注解,实现按需加载 Bean:

// ========== 类路径条件 ==========
@Configuration
@ConditionalOnClass(DataSource.class)  // 类路径存在 DataSource 才加载
public class DataSourceAutoConfiguration {
    // ...
}

// ========== Bean 存在条件 ==========
@Configuration
@ConditionalOnBean(DataSource.class)        // 容器中有 DataSource Bean
@ConditionalOnMissingBean(JdbcTemplate.class)  // 容器中没有 JdbcTemplate
public class JdbcTemplateConfiguration {
    // ...
}

// ========== 表达式条件 ==========
@Configuration
@ConditionalOnExpression("${app.feature.enabled} and ${app.feature.premium:false}")
public class PremiumFeatureConfiguration {
    // ...
}

// ========== 资源条件 ==========
@Configuration
@ConditionalOnResource(resources = "classpath:custom-config.properties")
public class CustomConfiguration {
    // ...
}

// ========== Web 应用条件 ==========
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class WebMvcConfiguration {
    // ...
}

6.1 @ConditionalOnProperty 详解

@ConditionalOnProperty 是最常用的条件注解,根据配置属性决定是否加载 Bean。

6.1.1 基本参数

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
    
    /**
     * 属性名前缀,与 name 拼接成完整属性名
     * 例如:prefix = "app.cache", name = "enabled" → app.cache.enabled
     */
    String prefix() default "";
    
    /**
     * 属性名,支持数组形式(多个属性时,都满足才匹配)
     */
    String[] name();
    
    /**
     * 期望的属性值,属性值等于此值才匹配
     * 如果不指定,则只要属性存在且不为 false 就匹配
     */
    String havingValue() default "";
    
    /**
     * 属性不存在时是否匹配
     * true: 属性不存在时也加载
     * false: 属性不存在时不加载(默认)
     */
    boolean matchIfMissing() default false;
}

6.1.2 常见用法

场景一:开关控制

// application.yml
app:
  cache:
    enabled: true

// 配置类
@Configuration
@ConditionalOnProperty(prefix = "app.cache", name = "enabled", havingValue = "true")
public class CacheConfiguration {
    // 只有 app.cache.enabled=true 时才加载
}

// 等价写法(不指定 havingValue,只要属性存在且不为 false)
@Configuration
@ConditionalOnProperty(prefix = "app.cache", name = "enabled")
public class CacheConfiguration {
    // app.cache.enabled=true 或 app.cache.enabled=1 都会加载
    // app.cache.enabled=false 不会加载
}

场景二:默认启用

// matchIfMissing = true 表示属性不存在时也加载
@Configuration
@ConditionalOnProperty(
    prefix = "app.feature",
    name = "enabled",
    havingValue = "true",
    matchIfMissing = true  // 属性不存在时默认加载
)
public class FeatureConfiguration {
    // 属性不存在 或 app.feature.enabled=true 时加载
    // app.feature.enabled=false 时不加载
}

场景三:多值选择

// application.yml
app:
  database:
    type: mysql  // 可选:mysql, postgresql, oracle

// MySQL 配置
@Configuration
@ConditionalOnProperty(prefix = "app.database", name = "type", havingValue = "mysql")
public class MySqlConfiguration {
    // app.database.type=mysql 时加载
}

// PostgreSQL 配置
@Configuration
@ConditionalOnProperty(prefix = "app.database", name = "type", havingValue = "postgresql")
public class PostgreSqlConfiguration {
    // app.database.type=postgresql 时加载
}

// Oracle 配置
@Configuration
@ConditionalOnProperty(prefix = "app.database", name = "type", havingValue = "oracle")
public class OracleConfiguration {
    // app.database.type=oracle 时加载
}

场景四:多属性条件

// name 支持数组,所有属性都满足才匹配
@Configuration
@ConditionalOnProperty(
    prefix = "app.security",
    name = {"enabled", "jwt.enabled"},  // 两个属性都要满足
    havingValue = "true"
)
public class JwtSecurityConfiguration {
    // app.security.enabled=true 且 app.security.jwt.enabled=true 时加载
}

场景五:方法级别条件

@Configuration
public class DataSourceConfiguration {
    
    @Bean
    @ConditionalOnProperty(prefix = "app.datasource", name = "type", havingValue = "hikari")
    public DataSource hikariDataSource() {
        return new HikariDataSource();
    }
    
    @Bean
    @ConditionalOnProperty(prefix = "app.datasource", name = "type", havingValue = "druid", matchIfMissing = true)
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
}

6.1.3 匹配规则详解

┌─────────────────────────────────────────────────────────────────────────┐
│  @ConditionalOnProperty 匹配规则                                         │
├─────────────────────────────────────────────────────────────────────────┤
│  属性状态          │ havingValue="" │ havingValue="true" │ matchIfMissing │
├─────────────────────────────────────────────────────────────────────────┤
│  属性存在 = true   │ ✅ 匹配        │ ✅ 匹配             │ -              │
│  属性存在 = false  │ ❌ 不匹配      │ ❌ 不匹配           │ -              │
│  属性存在 = "abc"  │ ✅ 匹配        │ ❌ 不匹配           │ -              │
│  属性存在 = "true" │ ✅ 匹配        │ ✅ 匹配             │ -              │
│  属性不存在        │ ❌ 不匹配      │ ❌ 不匹配           │ ✅ 匹配        │
└─────────────────────────────────────────────────────────────────────────┘

关键点:

  1. 不指定 havingValue:只要属性存在且值不为 false 就匹配
  2. 指定 havingValue:属性值必须等于 havingValue 才匹配
  3. matchIfMissing=true:属性不存在时也匹配(常用于默认启用场景)
  4. 属性值忽略大小写havingValue = "true" 匹配 TRUETruetrue

6.1.4 实战示例

示例一:多环境配置

// application-dev.yml
app:
  env: dev
  
// application-prod.yml
app:
  env: prod

// 开发环境配置
@Configuration
@ConditionalOnProperty(name = "app.env", havingValue = "dev")
public class DevConfiguration {
    @Bean
    public DataSource devDataSource() {
        // 开发环境使用 H2 内存数据库
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .build();
    }
}

// 生产环境配置
@Configuration
@ConditionalOnProperty(name = "app.env", havingValue = "prod")
public class ProdConfiguration {
    @Bean
    public DataSource prodDataSource() {
        // 生产环境使用真实数据库
        return new HikariDataSource();
    }
}

示例二:功能开关

// application.yml
app:
  features:
    async-enabled: true
    cache-enabled: false
    metrics-enabled: true

// 异步功能
@Configuration
@ConditionalOnProperty(prefix = "app.features", name = "async-enabled", havingValue = "true")
@EnableAsync
public class AsyncConfiguration {
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        return executor;
    }
}

// 缓存功能
@Configuration
@ConditionalOnProperty(prefix = "app.features", name = "cache-enabled", havingValue = "true")
@EnableCaching
public class CacheConfiguration {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

// 监控功能(默认启用)
@Configuration
@ConditionalOnProperty(
    prefix = "app.features", 
    name = "metrics-enabled", 
    havingValue = "true",
    matchIfMissing = true
)
public class MetricsConfiguration {
    @Bean
    public MeterRegistry meterRegistry() {
        return new SimpleMeterRegistry();
    }
}

示例三:条件组合

// 多条件组合:属性条件 + Bean 条件
@Configuration
@ConditionalOnProperty(prefix = "app.kafka", name = "enabled", havingValue = "true")
@ConditionalOnClass(KafkaTemplate.class)  // 类路径存在 Kafka 依赖
public class KafkaConfiguration {
    
    @Bean
    @ConditionalOnMissingBean  // 没有自定义 KafkaTemplate 时才创建
    public KafkaTemplate<String, String> kafkaTemplate(ProducerFactory<String, String> factory) {
        return new KafkaTemplate<>(factory);
    }
}

6.2 自定义条件

// 1. 实现 Condition 接口
public class OnLinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return System.getProperty("os.name").toLowerCase().contains("linux");
    }
}

// 2. 创建条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnLinuxCondition.class)
public @interface ConditionalOnLinux {
}

// 3. 使用自定义条件
@Configuration
@ConditionalOnLinux
public class LinuxSpecificConfiguration {
    // 仅在 Linux 系统加载
}

7. 循环依赖问题

循环依赖是 Spring 开发中常见的问题,需要正确理解和处理:

// ========== 问题场景 ==========
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;  // A 依赖 B
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;  // B 依赖 A → 循环依赖!
}

// ========== 解决方案一:重构设计(推荐)==========
// 提取公共逻辑到第三个 Service
@Service
public class CommonService {
    // 公共逻辑
}

@Service
public class ServiceA {
    @Autowired
    private CommonService commonService;
}

@Service
public class ServiceB {
    @Autowired
    private CommonService commonService;
}

// ========== 解决方案二:使用 @Lazy ==========
@Service
public class ServiceA {
    private final ServiceB serviceB;
    
    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB;  // 注入代理,延迟初始化
    }
}

// ========== 解决方案三:Setter 注入 ==========
@Service
public class ServiceA {
    private ServiceB serviceB;
    
    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

// ========== 解决方案四:使用 ApplicationContext ==========
@Service
public class ServiceA implements ApplicationContextAware {
    private ServiceB serviceB;
    
    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        this.serviceB = ctx.getBean(ServiceB.class);
    }
}

循环依赖处理机制:

Spring 三级缓存解决循环依赖:

singletonObjects(一级缓存)      → 完整的单例 Bean
earlySingletonObjects(二级缓存) → 早期暴露的 Bean(未完成属性注入)
singletonFactories(三级缓存)    → Bean 工厂,用于生成早期引用

处理流程:
1. A 实例化     → 放入三级缓存
2. A 注入 B     → B 不存在,创建 B
3. B 实例化     → 放入三级缓存
4. B 注入 A     → 从三级缓存获取 A 的早期引用
5. B 完成初始化  → 放入一级缓存
6. A 获取 B     → 从一级缓存获取 B
7. A 完成初始化  → 放入一级缓存

注意:构造器注入无法利用三级缓存解决循环依赖!

8. Bean 最佳实践总结

// ========== 推荐的 Bean 定义模板 ==========

// 1. 业务服务类
@Service
@Slf4j  // Lombok 日志
public class UserServiceImpl implements UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;
    
    // 构造器注入,final 字段保证不可变
    public UserServiceImpl(UserRepository userRepository, 
                          @Lazy EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
    
    @PostConstruct
    public void init() {
        log.info("UserService 初始化完成");
    }
    
    @Transactional(readOnly = true)
    @Override
    public Optional<UserDTO> findById(Long id) {
        return userRepository.findById(id)
            .map(this::toDTO);
    }
    
    @PreDestroy
    public void cleanup() {
        log.info("UserService 清理资源");
    }
}

// 2. 配置类
@Configuration
@EnableConfigurationProperties(AppProperties.class)
@ConditionalOnProperty(prefix = "app.feature", name = "enabled")
public class FeatureConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public FeatureService featureService(AppProperties properties) {
        return new FeatureService(properties);
    }
}

// 3. 配置属性类
@Data
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private boolean featureEnabled = false;
    private Duration timeout = Duration.ofSeconds(30);
}

核心原则:

  1. 单一职责:每个 Bean 只做一件事
  2. 构造器注入:强制依赖用构造器,可选依赖用 Setter
  3. 不可变优先:使用 final 字段,避免状态变更
  4. 避免循环依赖:通过重构设计解决,而非技术手段绕过
  5. 合理使用作用域:无状态用单例,有状态用原型/Request/Session
  6. 生命周期回调:初始化用 @PostConstruct,清理用 @PreDestroy
  7. 条件化加载:使用 @ConditionalXxx 实现按需加载

9. 相关阅读