Spring Bean方法返回this是否安全?原型、会话作用域下可正常使用吗
问题结论
1. Prototype作用域Bean的当前写法并不安全
你当前的代码存在根本性的使用错误,风险如下:
- Spring的Singleton Bean的依赖注入只会在容器初始化时执行一次,你注入到
SomeSingletonBean里的ReportGenerator实例全局唯一,并不会随着每次doSomeWork调用生成新的原型实例。多次调用doSomeWork会导致lines列表持续累加旧数据,多线程场景下还会出现并发修改的线程安全问题。 - 链式调用返回
this的写法本身没有问题,问题出在原型Bean的注入方式不对。只要保证每次执行业务逻辑时拿到的是全新的原型实例,链式调用就是完全安全的。
推荐修正方案:使用ObjectProvider动态获取原型实例,示例代码如下:
@Component public class SomeSingletonBean{ @Autowired private ObjectProvider<ReportGenerator> reportGeneratorProvider; void doSomeWork(){ // 每次调用都主动获取全新的原型实例 ReportGenerator rg = reportGeneratorProvider.getObject(); rg.append("a").append("b"); // 后续处理生成的报表内容 } }
你也可以选择使用@Lookup注解、直接从ApplicationContext中调用getBean的方式获取新实例,都可以解决上述问题。
2. Session作用域Bean可以安全使用返回this的链式写法,但需满足两个前提
- 注入时必须配置代理模式:如果要将Session作用域的Bean注入到Singleton Bean中,需要在Scope注解上指定代理模式,示例:
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS),否则容器启动会报错,也无法正常绑定会话对应的Bean实例。 - 避免同一会话内的并发修改:Session作用域的Bean绑定到单个用户的整个会话周期,同一个会话的多个并发请求会共享同一个Bean实例,如果存在多个请求同时修改Bean状态的场景,会出现数据错乱,你需要自行保证同一会话内不会并发修改该Bean的状态,或者对操作加锁。
只要满足以上两个条件,返回this的链式调用在Session作用域Bean上也可以正常使用。
内容的提问来源于stack exchange,提问作者Marinos An
相关产品推荐
相关产品推荐

