Spring MVC单例与多例

Spring MVC默认单例多线程的,使用ThreadLocal来切换线程之前的参数,Spring 把每个线程可能存在线程安全问题的参数值放进了 ThreadLocal,实现不同线程下的数据相互隔离。用ThreadLocal来保证线程安全,ThreadLoacalkey 就是当前线程的 Thread 实例。
Spring推荐配置就是单例,不用每次都 new , 高并发下能极大的节省资源,提高服务抗压能力。Spring IOC的 Bean 管理器是绝对的线程安全
Sprinv MVC Controller也可以通过注解@Scope("prototype")配置为多例模式。

单例与双例

  • 单例
    1. SpringMVC默认的配置是单例,只有一个实例处理所有请求。
    2. 普通属性静态属性 都会被共享共用。
  • 多例
    1. 普通属性不会共用的;而静态属性会被共用。
    2. SpringMVC Controller如果要改为多例,需要类上添加范围注解Scope("prototype")

示例代码

示例代码,定义一个 普通变量,一个 静态变量,通过多线程来查看结果,创建3条线程,每条线程执行3次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/demo")
//@Scope("prototype")
@Scope("singleton")
public class TestController {
private int num = 0;
private static int staticNum = 0;

@RequestMapping("/test1")
@ResponseBody
public String getTest() {
return "num = " + (num++) + "; staticNum =" + (staticNum++);
}
}
  1. 使用默认模式:不添加作用域注解Scope(),输出结果如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Thread-0: num = 0; staticNum =0
    Thread-2: num = 2; staticNum =1
    Thread-1: num = 1; staticNum =2
    Thread-0: num = 4; staticNum =4
    Thread-2: num = 3; staticNum =3
    Thread-1: num = 4; staticNum =4
    Thread-1: num = 5; staticNum =5
    Thread-0: num = 6; staticNum =6
    Thread-2: num = 6; staticNum =6
  2. 使用单例模式:添加单例注解Scope("singleton"),输出结果如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Thread-0: num = 0; staticNum =0
    Thread-1: num = 1; staticNum =1
    Thread-2: num = 2; staticNum =2
    Thread-2: num = 3; staticNum =3
    Thread-1: num = 4; staticNum =4
    Thread-0: num = 4; staticNum =4
    Thread-2: num = 6; staticNum =7
    Thread-1: num = 5; staticNum =6
    Thread-0: num = 5; staticNum =5
  3. 使用多例模式:添加多例注解Scope("prototype"),输出结果如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Thread-0: num = 0; staticNum =0
    Thread-1: num = 0; staticNum =2
    Thread-2: num = 0; staticNum =1
    Thread-0: num = 0; staticNum =3
    Thread-1: num = 0; staticNum =3
    Thread-2: num = 0; staticNum =4
    Thread-0: num = 0; staticNum =5
    Thread-2: num = 0; staticNum =7
    Thread-1: num = 0; staticNum =6

结论:SpringMVC 默认是单例模式,普通属性和静态属性都会被共享;打开多例模工,只有静态属性会被共享。
补充: Struts2 默认是多例的,会对每一个请求创建一个实例来处理。但与 Spring 结合使用则会变成单例,原因是 Action 委托给 Spring 管理,从 Spring IOC容器取出对象,而 Spring 容器默认是单例的,对 Bean 只实例化一次。Struts2 一定要使用多例模式,在 bean 配置添加作用域的属性 scope="prototype" ,否则默认单例模式在并发情况下与其它不同请求会产生窜数据的问题。

作者

光星

发布于

2018-01-05

更新于

2022-06-17

许可协议

评论