Spring中的Controller是單例的(原因和問題)
阿新 • • 發佈:2019-01-05
問題:如果Controller類是單例,那麼多個執行緒請求同一個Controller類中的同一個方法,執行緒是否會堵塞在Spring3中,Controller預設是單例的。如果Controller中有個私有的變數a,那麼所有請求到Controller中,使用的a變數是共用的。即某個請求要是修改了這個變數a,那麼在別的請求中也是可以讀到這個修改的內容的。<p>若是在@controller之前增加@Scope("prototype"),就可以改變單例模式為多例模式。</p> package com.xcesys.extras.webapp.controller.system; 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 @RequestMapping(value = "admin/system/example") public class ExampleAction { //定義一個變數 private int singletonInt = 1; @RequestMapping(value="/test") @ResponseBody public String singleton(HttpServletResponse response,HttpServletRequest request){ String data = request.getParameter("data"); if(data != null && data.length()>0){ int paramInt = Integer.parseInt(data); singletonInt = singletonInt + paramInt; }else{ singletonInt+=1000; } return String.valueOf(singletonInt); } } 輸入:http://localhost:8080/a/admin/system/example/test?data=15 輸出的結果是: <p>第一次: singletonInt=15</p><p>第二次: singletonInt=30</p><p>第三次: singletonInt=45</p>從以上結果可以得知,singletonInt的狀態是共享的,因此Controller是單例的。
@RequestMapping(value="/sleep") @ResponseBody public String switcher(HttpServletRequest request,HttpServletResponse response) throws InterruptedException{ String sleep = request.getParameter("sleep"); if(sleep.equals("on")){ Thread.currentThread().sleep(1000); return "sleep on"; }else{ return sleep; } }
驗證方法:分別傳送兩個請求,
第一個請求:http://localhost:8080/a/admin/system/example/sleep?sleep=on
第二個請求:http://localhost:8080/a/admin/system/example/sleep?sleep=test
驗證結果:第一個請求發出去以後,本地伺服器等待100s,然後返回結果"sleep on",在本地伺服器等待的者100s當中,傳送第二個請求,直接返回結果"test"。說明之間的執行緒是不互相影響的。
為什麼SpringMVC 要設計成單例模式的呢?
Spring的Bean作用域有5個:
1. singleton 單例模式,當spring建立applicationContext的時候,spring會初始化所有的該作用域例項,加上lazy-init就可以避免
2. prototype 原型模式,每次通過getBean獲取該Bean就會產生一個例項,建立之後spring將不再對其進行管理
3. request 每次請求都會產生一個請求域,spring依舊對其監聽
4. session 同上
5. global Session 全域性web域,類似servlet的application
1、為了效能。
2、不需要多例(上面的demo已經說明,在使用單例的時候,會改變其設定的變數)
最佳實踐:
1、不要在controller中定義成員變數。(在工作中的程式設定,是絕對不允許的)
2、萬一必須要定義一個非靜態成員變數時候,則通過註解@Scope("prototype"),將其設定為多例模式。