本文轉載自:http://md20040208.blog.163.com/blog/static/3006942720107208164038/
struts2-spring-plugin.jar的一些感悟
在我們集成struts2+spring+hibernate,也就是所謂的S2SH,不可避免的要引入struts2-spring-plugin.jar插件。當引入這個插件後,原先所struts創建的action類,交給了spring創建。在struts2-spring-plugin.jar中有一個struts-plugin.xml,裏面聲明瞭action類由spring工廠創建。在struts2插件文檔裏,這樣寫着“The Spring Plugin works by overriding the Struts ObjectFactory to enhance the creation of core framework objects。”這個插件重寫了struts的對象工廠,當創建一個action類時,它會根據struts的配置文件的class屬性的值與spring配置文件中的id屬性的值相匹配。如果沒有與之相匹配,將會像沒有使用這個插件前一樣創建,然後由spring自動裝配。
那時我有些不是很明白,爲什麼我的action類沒有寫註解@Component("xxAction"),還是可以被spring自動裝配。那是因爲action類被struts和struts2-spring-plugin創建,再由spring自動裝配,但不由spring管理。如果我們想使用spring複雜的aop或spring其他的功能時,強烈建議將acion類註冊到spring容器中。
今天,再次做測試,又有了出乎意料的結果。在此說明,我的測試中用的是annotion註解,不是xml文件。
之前,我們說過,當創建一個action類時,它會根據struts的配置文件的class屬性的值與spring配置文件中的id屬性的值相匹配。如果沒有與之相匹配,將會像沒有使用這個插件前一樣創建,然後由spring自動裝配。這兩種情況會出現不同的結果。現在我們慢慢來說明。
假設我們有一個AddUserAction的類,位於com.action包下,它有屬性userService:
package com.action;
import com.opensymphony.xwork2.ActionSupport;
import com.service.UserService;
public class AddUserAction extends ActionSupport {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public String execute() throws Exception {
System.out.println(userService==null);
return SUCCESS;
}
}
以上這個類是我們最簡單的action類,在沒有引入struts2-spring-plugin.jar插件時,action類是由struts創建的,我們struts.xml文件是這樣寫的:
<struts>
<package name="registration" extends="struts-default">
<action name="addUser" class="com.action.AddUserAction">
<result>success.jsp</result>
</action>
</package>
</struts>
但如果我們引入struts2-spring-plugin.jar插件後,如果我們的struts.xml文件還是如同以上一樣寫,就會出現struts的配置文件的class屬性的值與spring配置文件中的id屬性的值不匹配,因爲action類沒有註冊到spring的容器中。那action的創建由strutst和struts2-spring-plugin.jar插件創建,默認地根據名字到spring容器中去找相應的對象進行自動裝配(不管你是否願意,只要提供了set方法),所以userService不會是null值,這個action類的scope也默認的是prototype,但這個action類不在spring容器中。
自然的,以上這種情況不是我們想要的,因爲很多情況都不在我們的控制範圍內。那隻要我們將action類的創建交給spring,就可以自主也配置我們想要的屬性。這時我們將原來的action類改爲:
package com.action;
mport javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
import com.service.UserService;
@Component("addUserAction")
@Scope("prototype")
public class AddUserAction extends ActionSupport {
private UserService userService;
@Resource(name="userService")
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public String execute() throws Exception {
System.out.println(userService==null);
return SUCCESS;
}
}
在第二個action類中,我們加入了相應的annotion,把我們的action類註冊到spring容器中。我們的struts.xml文件也改爲:
<struts>
<package name="registration" extends="struts-default">
<action name="addUser" class="addUserAction">
<result>success.jsp</result>
</action>
</package>
</struts>
這時,struts的配置文件的class屬性的值與spring配置文件中的id屬性的值匹配。如果我們不想裝配userService,可以將@Resource(name="userService")刪除。
所以,在struts.xml裏的class的屬性值決定你以那種方式創建action類,我個人傾向於將action類交給spring管理和自動裝配。
如果有什麼不正確的地方,歡迎大家指出。