
spring 默认创建的单例 bean 是全局共享的,若在其中修改可变状态(如普通成员变量),该变更将影响所有线程和请求——因此单例 bean 必须无状态或严格同步,否则将引发严重的并发安全问题。
在 Spring 应用中,绝大多数 Bean(如 @Service、@Repository、@Component)默认以 singleton 作用域创建,即整个 Spring 容器中仅存在一个实例。这个实例被所有请求、线程和组件共享。关键点在于:共享的是对象引用本身——如果该 Bean 包含可变的非线程安全字段(例如 private String currentUser; 或 private Map
✅ 正确实践:保持 Bean 无状态
@Service
public class OrderService {
// ✅ 推荐:不维护请求/调用相关的状态
public Order createOrder(User user, List- items) {
// 所有状态均来自方法参数或局部变量
BigDecimal total = items.stream()
.map(Item::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
return new Order(user.getId(), items, total);
}
}
❌ 危险示例:在单例 Bean 中存储请求上下文
@Service
public class UnsafeContextService {
private String currentTenantId; // ❌ 共享字段,多线程下互相覆盖!
public void processForTenant(String tenantId) {
this.currentTenantId = tenantId; // ⚠️ 此赋值会影响其他线程!
// 后续逻辑误用 this.currentTenantId → 数据错乱
}
}⚠️ 注意事项:
- 不要将请求级、用户级或事务级状态存入 singleton Bean 的成员变量中;应使用 ThreadLocal(需谨慎管理生命周期)、方法参数、或 Spring 提供的上下文抽象(如 RequestContextHolder、SecurityContextHolder);
- 若确实需要有状态的 Bean,请显式声明作用域:@Scope("prototype")(每次注入新建实例)或 @Scope("request")(Web 环境中每个 HTTP 请求独立实例);
- 使用 @Value、@ConfigurationProperties 注入的配置类也应设计为不可变(final 字段 + 构造器注入),避免运行时意外修改。
? 总结:Spring 的 IoC 容器负责对象生命周期管理,而非线程安全保证。开发者必须主动规避共享可变状态——这是构建高并发、可伸缩 Spring 应用的基本前提。










