Spring中Controller单例
- controller默认是单例的,不要使用非静态的成员变量,否则会发生数据逻辑混乱。 正因为单例所以不是线程安全的。
我们下面来简单的验证下:
1 | package com.riemann.springbootdemo.controller; |
得到的不同的值,这是线程不安全的。
接下来我们再来给controller增加作用多例 @Scope(“prototype”)
1 | package com.riemann.springbootdemo.controller; |
- 我们依旧首先访问 http://localhost:8080/testScope,得到的答案是1;
- 然后我们再访问 http://localhost:8080/testScope2,得到的答案还是 1。
相信大家不难发现 :
单例是不安全的,会导致属性重复使用。
解决方案
- 不要在controller中定义成员变量。
- 万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。
- 在Controller中使用ThreadLocal变量
Spring MVC默认是单例模式,Controller、Service、Dao都是单例所以在使用不当存在一定的安全隐患。Controller单例模式的好处在与:
- 提高性能,不用每次创建Controller实例,减少了对象创建和垃圾收集的时间
- 没多例的必要,由于只有一个Controller的实例,当多个线程同时调用它的时候,它的成员变量就不是线程安全的。
当然在大多数情况下,我们根本不需要Controller考虑线程安全的问题,除非在类中声明了成员变量。因此Spring MVC的Controller在编码时,尽量避免使用实例变量。如果一定要使用实例变量,则可以改用以下方式:
Controller中声明 scope=”prototype”,即设置为多例模式
在Controller中使用ThreadLocal变量,如:private ThreadLocal count = new ThreadLocal();
springmvc singleton有几种解决方法:
1、在控制器中不使用实例变量(可以使用方法参数的形式解决,参考博文 Spring Bean Scope 有状态的Bean 无状态的Bean)
2、将控制器的作用域从单例改为原型,即在spring配置文件Controller中声明 scope=“prototype”,每次都创建新的controller
3、在Controller中使用ThreadLocal变量