首先對於Spring的IOC來說,對象是由Spring來幫我們管理,也就是在Spring啟動的時候,在Spring容器中,由Spring給我們建立的,Spring會幫我們維護,一般都是單例的,也就是一個對象。
spring產生對象預設是單例的。通過scope屬性可以更改為多例。
第一部分:驗證Spring產生對象預設是單例的。
下面我們來一個網上的例子驗證一下:
[html] view plain copy print ? <bean id="singleton" class="java.util.Date" scope="singleton"></bean> <bean id="prototype" class="java.util.Date" scope="prototype"></bean>
<bean id="singleton" class="java.util.Date" scope="singleton"></bean><bean id="prototype" class="java.util.Date" scope="prototype"></bean>
[java] view plain copy print ? 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)); } }
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中定義執行個體變數。
如:
[java] view plain copy print ? public class Controller extends AbstractCommandController { protected Company company; protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors) throws Exception { company = ................; } }
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都是單例的。
例如:
[java] view plain copy print ? @Controller @RequestMapping("/fui") public class FuiController extends SpringController { //這麼定義的話就是單例 @Controller @Scope("prototype") @RequestMapping("/fui") public class FuiController extends SpringController { //每次都建立
@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"。
[java] view plain copy print ? <bean id="user" class="modle.User" scope="prototype"></bean>
<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設定檔中找。