spring MVC中的controller是怎么實現線程安全的


首先對於spring的IOC來說,對象是由Spring來幫我們管理,也就是在Spring啟動的時候,在Spring容器中,由Spring給我們創建的,Spring會幫我們維護,一般都是單例的,也就是一個對象。

 

spring生成對象默認是單例的。通過scope屬性可以更改為多例。

 1、scope=singleton ,默認是單例的,這樣就會多個線程共用一個controller,在沒有共享變量的情況下,線程是安全的。

2、scope=prototype,每個線程會新建一個controller,不會存在線程安全問題。

第一部分:驗證Spring生成對象默認是單例的。

 

下面我們來一個網上的例子驗證一下:

[html]  view plain  copy print?
  1. <bean id="singleton" class="java.util.Date" scope="singleton"></bean>  
  2. <bean id="prototype" class="java.util.Date" scope="prototype"></bean>  
[java]  view plain  copy print?
  1. package test;   
  2. import java.util.Date;  
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5. import com.opensymphony.xwork2.ActionContext;  
  6.   
  7. public class TestScope {  
  8.   
  9.     public static void main(String[] args) {  
  10.   
  11.        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-web.xml");  
  12.   
  13.        Date s1=(Date)context.getBean("singleton");  
  14.   
  15.        Date p1=(Date)context.getBean("prototype");  
  16.   
  17.        Date s2=(Date)context.getBean("singleton");  
  18.   
  19.        Date p2=(Date)context.getBean("prototype");  
  20.       
  21.        System.out.println("單例:"+(s1==s2));  
  22.   
  23.        System.out.println("非單例:"+(p1==p2));  
  24.   
  25.     }  
  26.   
  27.   
  28. }  


輸出結果:

結果

單例:true

非單例:false

 

注:復合數據類型的“== ”對比的是內存中存放的地址,所以此處我們采用“==”去對比

因為object中的equals初始行為是比較內存中的地址,但在一些類庫中被覆蓋掉了如(StringIntegerDate等)

 

第二部分:SpringMVC和Struts2中是並發訪問否會存在線程安全問題。

 

對於使用過SpringMVC和Struts2的人來說,大家都知道SpringMVC是基於方法的攔截,而Struts2是基於類的攔截。

 

對於Struts2來說,因為每次處理一個請求,struts就會實例化一個對象;這樣就不會有線程安全的問題了;

而Spring的controller默認是Singleton的,這意味着每一個request過來,系統都會用原有的instance去處理,這樣導致兩個結果:

一是我們不用每次創建Controller,二是減少了對象創建和垃圾收集的時間;由於只有一個Controller的instance,當多個線程調用它的時候,它里面的instance變量就不是線程安全的了,會發生竄數據的問題。

 

當然大多數情況下,我們根本不需要考慮線程安全的問題,比如dao,service等,除非在bean中聲明了實例變量。因此,我們在使用spring mvc 的contrller時,應避免在controller中定義實例變量。 
如:

 

[java]  view plain  copy print?
  1. public class Controller extends AbstractCommandController {    
  2.     protected Company company;  
  3.     protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors) throws Exception {  
  4.         company = ................;           
  5.      }             
  6.  }    


解決方案:

有幾種解決方法:
1、在Controller中使用ThreadLocal變量
2、在spring配置文件Controller中聲明 scope="prototype",每次都創建新的controller
所在在使用spring開發web 時要注意,默認Controller、Dao、Service都是單例的。

 

例如:

[java]  view plain  copy print?
  1. @Controller  
  2. @RequestMapping("/fui")  
  3. public class FuiController extends SpringController {  
  4. //這么定義的話就是單例  
  5.   
  6. @Controller  
  7. @Scope("prototype")  
  8. @RequestMapping("/fui")  
  9. public class FuiController extends SpringController {  
  10. //每次都創建  

 

第三部分:springMVC與struts2的區別。

 

下面是從網絡上摘抄的一段對比,大家可以看看

點擊打開鏈接

 

1. 機制:spring mvc的入口是servlet,而struts2是filter,這樣就導致了二者的機制不同。 

 

2. 性能:spring會稍微比struts快。spring mvc是基於方法的設計,而sturts是基於類,每次發一次請求都會實例一個action,每個action都會被注入屬性,而spring基於方法,粒度更細,但要小心把握像在servlet控制數據一樣。spring3 mvc是方法級別的攔截,攔截到方法后根據參數上的注解,把request數據注入進去,在spring3 mvc中,一個方法對應一個request上下文。而struts2框架是類級別的攔截,每次來了請求就創建一個Action,然后調用setter getter方法把request中的數據注入;struts2實際上是通過setter getter方法與request打交道的;struts2中,一個Action對象對應一個request上下文。 

 

3. 參數傳遞:struts是在接受參數的時候,可以用屬性來接受參數,這就說明參數是讓多個方法共享的。

 

4. 設計思想上:struts更加符合oop的編程思想, spring就比較謹慎,在servlet上擴展。 

 

5. intercepter的實現機制:struts有以自己的interceptor機制,spring mvc用的是獨立的AOP方式。這樣導致struts的配置文件量還是比spring mvc大,雖然struts的配置能繼承,所以我覺得論使用上來講,spring mvc使用更加簡潔,開發效率Spring MVC確實比struts2高。spring mvc是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上spring3 mvc就容易實現restful url。struts2是類級別的攔截,一個類對應一個request上下文;實現restful url要費勁,因為struts2 action的一個方法可以對應一個url;而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標識其所屬方法了。spring3 mvc的方法之間基本上獨立的,獨享request response數據,請求數據通過參數獲取,處理結果通過ModelMap交回給框架方法之間不共享變量,而struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變量是共享的,這不會影響程序運行,卻給我們編碼,讀程序時帶來麻煩。 

 

6. 另外,spring3 mvc的驗證也是一個亮點,支持JSR303,處理ajax的請求更是方便,只需一個注解@ResponseBody ,然后直接返回響應文本即可。

 

總結:

 

這樣也說明了SpringMVC還有Servlet都是方法的線程安全,所以在類方法聲明的私有或者公有變量不是線程安全的,而struts2的確實是線程安全的。

 

第四部分:那么對於Struts2+Spring來管理注入的時候呢?

 

Struts2它是多實例的,對於每個請求都會生成1個實例,spring默認是單實例的(下面針對Struts與Spring集成的兩種方式分別來介紹struts2和spring的兩種整合方式

一:對於無Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式,需要在spring的action Bean中加業務邏輯控制器類配scope="prototype"。

 

[java]  view plain  copy print?
  1. <bean id="user" class="modle.User" scope="prototype"></bean>  

 

:對於有Spring插件(Struts2-spring-plugin-XXX.jar)的整合方式:反編譯StrutsSpringObjectFactory以及相關的代碼才發現,如果在struts action的配置文件中<action name=".." class=".."/>中class寫的如果是完整的包名和類名的話就是struts創建action對象,也就是多實例的;

 

總結:如果是spring配置文件中的 bean的名字的話就是spring創建,那么單實例還是多實例就由spring的action Bean中的業務邏輯控制器類是否配置為scope=”prototype”,有就是多實例的,沒有就是單實例的,順序是先從spring中找,找不到再從struts配置文件中找。

轉自 :http://blog.csdn.net/hejingyuan6/article/details/50363647


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM