SpringMVC Controller默認情況下是Singleton(單例)的,當request過來,不用每次創建Controller,會用原來的instance去處理。那么當多個線程調用它的時候,會不會發生線程不安全呢?
1、先說明下 Controller默認情況 單例的問題:
使用Spring MVC有一段時間了,之前一直使用Struts2,在struts2中action都是原型(prototype)的, 說是因為線程安全問題,對於Spring MVC中bean默認都是(singleton)單例的,那么用@Controller注解標簽注入的Controller類是單例實現的?
測試結果發現spring3中的controller默認是單例的,若是某個controller中有一個私有的變量i,所有請求到同一個controller時,使用的i變量是共用的,即若是某個請求中修改了這個變量a,則,在別的請求中能夠讀到這個修改的內容。 若是在@Controller之前增加@Scope(“prototype”),就可以改變單例模式為多例模式
以下是測試步驟,代碼與結果.
1. 如果是單例類型類的,那么在Controller類中的類變量應該是共享的,如果不共享,就說明Controller類不是單例。以下是測試代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.springframework.stereotype.Controller;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.ResponseBody;
@Controller
public
class
ExampleAction {
private
int
singletonInt=
1
;
@RequestMapping
(value =
"/test"
)
@ResponseBody
public
String singleton(HttpServletRequest request,
HttpServletResponse response)
throws
Exception {
String data=request.getParameter(
"data"
);
if
(data!=
null
&&data.length()>
0
){
try
{
int
paramInt= Integer.parseInt(data);
singletonInt = singletonInt + paramInt;
}
catch
(Exception ex){
singletonInt+=
10
;
}
}
else
{
singletonInt+=
1000
;
}
return
String.valueOf(singletonInt);
}
}
|
分別三次請求: http://localhost:8080/example/test.do?data=15
得到的返回結果如下。
第一次: singletonInt=15
第二次: singletonInt=30
第三次: singletonInt=45
從以上結果可以得知,singletonInt的狀態是共享的,因此Controller是單例的。
2、對別Struts與springmvc對比
Struts2 :默認prototype,Struts2 是基於類的,處於線程安全的考慮,采用了prototype模式,也就是說每次請求都會新建一個類來處理,自然就沒有線程安全問題了,每次請求的類和數據都是單獨的。
Springmvc :默認singleton 單例模式,Springmvc 是基於方法的,同一個url的請求是同一個實例處理的。每次請求都會把請求參數傳遞到同一個方法中,此時如果類里面有成員變量,那么這個變量就不是線程安全的了(例如上面的例子 private
int
singletonInt=
1
; 這個變量如果想線程安全則可以用ThreadLocal
)。
在類中沒有成員變量的前提下則是線程安全的。
參考:https://zhuanlan.zhihu.com/p/103171449
https://blog.csdn.net/sinat_30474567/article/details/64924927