spring原始碼分析-controller的執行緒安全
阿新 • • 發佈:2019-02-03
大家都知道,struts1.2由於是執行緒安全的,每一個請求都去例項化一個action,造成大量併發時的資源浪費。
struts2在這一點上做了改進,每個action都是一個singleton,所有的請求都是請求同一個action例項。這樣在一定程度上能節約資源,但又有安全問題。最常見的就是在action中宣告有塊狀的例項變數,因為這一點是不被提倡的。如果一定要宣告,那一定要加上同步塊。
那麼在spring mvc中的controller是不是執行緒安全的呢?答案是否定的。controller在預設情況下也是非執行緒安全的,我們來看看原始碼:
Java程式碼
由上面原始碼可知,controller預設是非安全的。
Java程式碼
只有手工設定controller的synchronizeOnSession值為true,才會被同步處理。
因此,我們在使用spring mvc 的contrller時,應避免在controller中定義例項變數。
##### 更正 ####################################
由於在下對struts1.x的理解也來自網路,給大家帶來不便,還請見諒。
經過對struts1.x原始碼的研讀發現:
struts1.2獲取action的方式是單例的,所有的action都被維護在一個hashMap裡,當有請求到達時,先根據action的名稱去hashMap裡查詢要請求的Action是否已經存在,如果存在,則直接返回hashMap裡的action。如果不存在,則建立一個新的Action例項。
下面我們來分析一下原始碼:
請求到達ActionServlet時,首先會到達doGet()或doPost()方法,而ActionServlet轉給了process()方法進行統一處理
Java程式碼
而process()方法又會轉給processor的process()方法進行處理
Java程式碼
processor的process()方法裡經過一系列處理後,最後通過processActionCreate方法來返回一個具體的action例項
Java程式碼
那我們就到processActionCreate這個方法裡去一窺究竟吧:
1、先獲取類名
2、根據類名去map裡查尋例項是否已經存在
3、如果存在,則直接返回
4、如果不存在,則建立一個新例項
5、把建立好的action放到map裡備用
Java程式碼
我們再來看看actions的定義:
Java程式碼
結論:
struts1.2獲取action的方式是單例的,所有的action都被維護在一個hashMap裡,當有請求到達時,先根據action的名稱去hashMap裡查詢要請求的Action是否已經存在,如果存在,則直接返回hashMap裡的action。如果不存在,則建立一個新的Action例項。
struts2在這一點上做了改進,每個action都是一個singleton,所有的請求都是請求同一個action例項。這樣在一定程度上能節約資源,但又有安全問題。最常見的就是在action中宣告有塊狀的例項變數,因為這一點是不被提倡的。如果一定要宣告,那一定要加上同步塊。
那麼在spring mvc中的controller是不是執行緒安全的呢?答案是否定的。controller在預設情況下也是非執行緒安全的,我們來看看原始碼:
Java程式碼
-
* @author
- * @author Juergen Hoeller
- * @since 2.0
- * @see ResourceAwareController
- * @see EventAwareController
- */
- public abstract class AbstractController extends PortletContentGenerator implements Controller {
- [color=red]private boolean synchronizeOnSession = false;[/color]
由上面原始碼可知,controller預設是非安全的。
Java程式碼
- public void handleActionRequest(ActionRequest request, ActionResponse response) throws Exception {
- // Delegate to PortletContentGenerator for checking and preparing.
- check(request, response);
- // Execute in synchronized block if required.
-
//只有synchronizeOnSession設定為true,才會同步處理請求
- if (this.synchronizeOnSession) {
- PortletSession session = request.getPortletSession(false);
- if (session != null) {
- synchronized (session) {
- handleActionRequestInternal(request, response);
- return;
- }
- }
- }
- handleActionRequestInternal(request, response);
- }
只有手工設定controller的synchronizeOnSession值為true,才會被同步處理。
因此,我們在使用spring mvc 的contrller時,應避免在controller中定義例項變數。
##### 更正 ####################################
由於在下對struts1.x的理解也來自網路,給大家帶來不便,還請見諒。
經過對struts1.x原始碼的研讀發現:
struts1.2獲取action的方式是單例的,所有的action都被維護在一個hashMap裡,當有請求到達時,先根據action的名稱去hashMap裡查詢要請求的Action是否已經存在,如果存在,則直接返回hashMap裡的action。如果不存在,則建立一個新的Action例項。
下面我們來分析一下原始碼:
請求到達ActionServlet時,首先會到達doGet()或doPost()方法,而ActionServlet轉給了process()方法進行統一處理
Java程式碼
- public void doPost(HttpServletRequest request,
- HttpServletResponse response)
- throws IOException, ServletException {
- process(request, response);
- }
而process()方法又會轉給processor的process()方法進行處理
Java程式碼
- protected void process(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
- ...
- processor.process(request, response);
- }
processor的process()方法裡經過一系列處理後,最後通過processActionCreate方法來返回一個具體的action例項
Java程式碼
- public void process(HttpServletRequest request,
- HttpServletResponse response)
- throws IOException, ServletException {
- ...
- // Create or acquire the Action instance to process this request
- Action action = processActionCreate(request, response, mapping);
- if (action == null) {
- return;
- }
- ...
- }
那我們就到processActionCreate這個方法裡去一窺究竟吧:
1、先獲取類名
2、根據類名去map裡查尋例項是否已經存在
3、如果存在,則直接返回
4、如果不存在,則建立一個新例項
5、把建立好的action放到map裡備用
Java程式碼
- protected Action processActionCreate(HttpServletRequest request,
- HttpServletResponse response,
- ActionMapping mapping)
- throws IOException {
- // Acquire the Action instance we will be using (if there is one)
- String className = mapping.getType();//1、先獲取類名
- ...
- Action instance = null;
- synchronized (actions) {
- // Return any existing Action instance of this class
- instance = (Action) actions.get(className);//2、根據類名去map裡查尋例項是否已經存在
- if (instance != null) {
- return (instance); //3、如果存在,則直接返回
- }
- // Create and return a new Action instance
- //4、如果不存在,則建立一個新例項
- instance = (Action) RequestUtils.applicationInstance(className)
- instance.setServlet(this.servlet);
- actions.put(className, instance);//5、把建立好的action放到map裡
- }
- ...
- return (instance);
- }
我們再來看看actions的定義:
Java程式碼
- /**
- * The set of Action instances that have been created and
- * initialized, keyed by the fully qualified Java class name of the
- * Action class.
- */
- protected HashMap actions = new HashMap();
結論:
struts1.2獲取action的方式是單例的,所有的action都被維護在一個hashMap裡,當有請求到達時,先根據action的名稱去hashMap裡查詢要請求的Action是否已經存在,如果存在,則直接返回hashMap裡的action。如果不存在,則建立一個新的Action例項。