首先對於spring的IOC來說,對象是由Spring來幫我們管理,也就是在Spring啟動的時候,在Spring容器中,由Spring給我們創建的,Spring會幫我們維護,一般都是單例的,也就是一個對象。
spring生成對象默認是單例的。通過scope屬性可以更改為多例。
1、scope=singleton ,默認是單例的,這樣就會多個線程共用一個controller,在沒有共享變量的情況下,線程是安全的。
2、scope=prototype,每個線程會新建一個controller,不會存在線程安全問題。
第一部分:驗證Spring生成對象默認是單例的。
下面我們來一個網上的例子驗證一下:
- <bean id="singleton" class="java.util.Date" scope="singleton"></bean>
- <bean id="prototype" class="java.util.Date" scope="prototype"></bean>
- package test;
- import java.util.Date;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.opensymphony.xwork2.ActionContext;
- public class TestScope {
- public static void main(String[] args) {
- ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-web.xml");
- Date s1=(Date)context.getBean("singleton");
- Date p1=(Date)context.getBean("prototype");
- Date s2=(Date)context.getBean("singleton");
- Date p2=(Date)context.getBean("prototype");
- System.out.println("單例:"+(s1==s2));
- System.out.println("非單例:"+(p1==p2));
- }
- }
輸出結果:
結果
單例:true
非單例:false
注:復合數據類型的“== ”對比的是內存中存放的地址,所以此處我們采用“==”去對比
因為object中的equals初始行為是比較內存中的地址,但在一些類庫中被覆蓋掉了如(String,Integer,Date等)
第二部分:SpringMVC和Struts2中是並發訪問否會存在線程安全問題。
對於使用過SpringMVC和Struts2的人來說,大家都知道SpringMVC是基於方法的攔截,而Struts2是基於類的攔截。
對於Struts2來說,因為每次處理一個請求,struts就會實例化一個對象;這樣就不會有線程安全的問題了;
而Spring的controller默認是Singleton的,這意味着每一個request過來,系統都會用原有的instance去處理,這樣導致兩個結果:
一是我們不用每次創建Controller,二是減少了對象創建和垃圾收集的時間;由於只有一個Controller的instance,當多個線程調用它的時候,它里面的instance變量就不是線程安全的了,會發生竄數據的問題。
當然大多數情況下,我們根本不需要考慮線程安全的問題,比如dao,service等,除非在bean中聲明了實例變量。因此,我們在使用spring mvc 的contrller時,應避免在controller中定義實例變量。
如:
- public class Controller extends AbstractCommandController {
- protected Company company;
- protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors) throws Exception {
- company = ................;
- }
- }
解決方案:
有幾種解決方法:
1、在Controller中使用ThreadLocal變量
2、在spring配置文件Controller中聲明 scope="prototype",每次都創建新的controller
所在在使用spring開發web 時要注意,默認Controller、Dao、Service都是單例的。
例如:
- @Controller
- @RequestMapping("/fui")
- public class FuiController extends SpringController {
- //這么定義的話就是單例
- @Controller
- @Scope("prototype")
- @RequestMapping("/fui")
- public class FuiController extends SpringController {
- //每次都創建
第三部分: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"。
- <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