Spring带参构造类能否替代@Autowired注入?现有实现是否存在问题
问题解答
现有实现的问题
你当前的写法是错误的,部署到Web环境一定会出现线程安全问题,原因如下:
@Service注解的Bean默认是单例,整个应用生命周期中只有一个TestService实例,所有请求共用这一个实例- 你将
Test t定义为TestService的成员变量,多线程并发调用m1方法时,多个请求会同时修改t的引用,出现值覆盖、逻辑错乱的问题。比如请求A传入参数z="张三"创建了Test实例还没完成后续逻辑,请求B传入z="李四"就把t的引用覆盖了,请求A后续使用t时拿到的就是李四的值,完全不符合预期。
正确的实现方案
你完全可以直接在方法内部定义Test实例,不需要将其作为成员变量,调整后的代码如下:
@Service class TestService implements Service{ @Autowired Repo repo; public void m1(String z){ // 直接在方法内声明Test为局部变量,线程隔离 Test t = new Test(z); // 后续逻辑 } }
这个方案是完全安全的:方法内的局部变量是每个线程独有的,存储在栈内存中,不同线程的调用完全隔离,不会出现并发修改问题。
补充说明:什么时候需要把Test交给Spring管理
如果你的Test类后续需要注入Spring容器中的其他Bean(比如需要注入Repo、其他Service等),才需要把Test纳入Spring生命周期管理,此时可以用以下方案:
- 给Test类添加
@Component和@Scope("prototype")注解,声明为原型Bean - 在TestService中注入
ApplicationContext,调用时传入构造参数获取实例:
@Service class TestService implements Service{ @Autowired Repo repo; @Autowired ApplicationContext context; public void m1(String z){ Test t = context.getBean(Test.class, z); // 后续逻辑 } }
你当前的Test类没有Spring依赖,不需要这么复杂,直接方法内new即可。
内容的提问来源于stack exchange,提问作者palak
相关产品推荐
相关产品推荐

