Spring Boot Bean 使用规范
理解 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" │ ✅ 匹配 │ ✅ 匹配 │ - │
│ 属性不存在 │ ❌ 不匹配 │ ❌ 不匹配 │ ✅ 匹配 │
└─────────────────────────────────────────────────────────────────────────┘关键点:
- 不指定 havingValue:只要属性存在且值不为
false就匹配 - 指定 havingValue:属性值必须等于 havingValue 才匹配
- matchIfMissing=true:属性不存在时也匹配(常用于默认启用场景)
- 属性值忽略大小写:
havingValue = "true"匹配TRUE、True、true
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);
}核心原则:
- 单一职责:每个 Bean 只做一件事
- 构造器注入:强制依赖用构造器,可选依赖用 Setter
- 不可变优先:使用 final 字段,避免状态变更
- 避免循环依赖:通过重构设计解决,而非技术手段绕过
- 合理使用作用域:无状态用单例,有状态用原型/Request/Session
- 生命周期回调:初始化用
@PostConstruct,清理用@PreDestroy - 条件化加载:使用
@ConditionalXxx实现按需加载
9. 相关阅读
- Spring Boot 启动原理 - 了解 Bean 加载的底层原理
- Spring Boot 常用注解 - 常用注解详解

