为了在Struts中加载Spring context,需要在struts-config.xml文件中加入如下部分:
<struts-config>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml" />
</plug-in>
</struts-config>
第一种方法:
通过Struts的plug-in在Struts和Spring之间提供了良好的结合点。通过plug-in我们实现了Spring context的加载,不过仅仅加载Spring context并没有什么实际的意义,还应该经过配置将Struts的Action交给Spring容器进行管理。
<action-mappings>
<action path="/login"
type="org.springframework.web.struts.DelegatingActionProxy"
name="loginForm">
<forward name="success" path="/main.jsp" />
<forward name="failure" path="/login.jsp" />
</action>
在form bean这个节点上与传统的Struts配置没有什么区别,而在Action上面则发生了变化。在传统的action节点上type属性写入action类的完整类名,而和Spring结合后在这点上是使用了Spring提供的DelegatingActionProxy作为action的type属性,DelegatingActionProxy同样是org.apache.struts.action.Action的一个子类,它将把调用请求转交给真正的Action实现。通过这样的方式,Spring获得了Action实例的管理权,它将对Action进行调度,并为Struts提供所需的Action实例。这样,就可以将Action看作是Spring的一个bean,它就可以享受Spring的所有服务,如依赖注入、实例管理、事务管理等。
在applicationContext.xml中相应的配置如下的节点:
<beans>
.......
<bean name="/login" class="net.xiaxin.action.LoginAction"
singleton="false">
<property name="userDAO">
<ref bean="userDAOProxy" />
</property>
</bean>
</beans>
最后这个bean的配置是关键,这个名为“/login”的bean与Struts中的
<action path="/login" ……>
……
</action>节点相对应,这样,Spring Bean Name与Struts Action Path相关联,当Struts加载对应的Action时,DelegatingActionProxy就根据传入的path属性,在Spring Context寻找对应bean,并将其实例返回给Struts。与此同时,还可以看到,"/login" bean 中包含了一个userDAO 引用,Spring 在运行期将根据配置为其提供userDAO 实例,以及围绕userDAO 的事务管理服务。这样一来,对于Struts 开发而言,我们既可以延续Struts 的开发流程,也可以享受Spring 提供的事务管
理服务。而bean 的另外一个属性singleton="false",指明了Action 的实例获取方式为每次重新创建。这也解决了Struts中令人诟病的线程安全问题。
第二种方法:
为了在 struts-config.xml 文件中配置 DelegatingRequestProcessor,你需要重载 <controller> 元素的 “processorClass” 属性。 下面的几行应该放在 <action-mapping> 元素的后面。
<controller>
<set-property property="processorClass"
value="http://www.zhmy.com/org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>
增加这些设置之后,不管你查询任何类型的 Action,Sping都自动在它的context配置文件中寻找。 实际上,你甚至不需要指定类型。下面两个代码片断都可以工作:
<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>
如果你使用 Struts 的 modules 特性,你的 bean 命名必须含有 module 的前缀。 举个例子,如果一个 Action 的定义为 <action path="/user"/>,而且它的 module 前缀为“admin”, 那么它应该对应名为 <bean name="/admin/user"/> 的 bean
如果你在 Struts 应用中使用了 Tiles,你需要配置 <controller> 为 DelegatingTilesRequestProcessor。
如果第二种方法不行,再用第一种方法。
至此,SS组合已经将Struts MVC以及Spring中的Bean管理、事务管理融为一体。如
果算上userDAO 中的Hibernate 部分,我们就获得了一个全面、成熟、高效、自顶而下的
Web 开发框架。
Struts+Spring整合方式
struts与spring整合方式有三种:
方式一:通过Spring的ActionSupport类实现。
方式二:通过Sping的DelegatingRequestProcessor类实现。
方式三:通过Sping的DelegatingActionProxy类实现。
相同点:以上三种方式都需要在struts的配置文件struts-config.xml中注册spring的ContextLoaderPlugIn插件。即:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
不同点:
使用Spring提供的ActionSupport类,只需要使用Action继承Spring的ActionSupport类,即可实现Spring与struts的整合,使用起来简单方便,但是struts的Action与Spring耦合在一起,并且Struts的Action不在spring的控制之中,这样如果更换别的IOC容器,或想使用Spring的AOP都是比较困难的,而且如果是多个动作放在一个Action中,则这种方式就无能为了了!
使用Spring的DelegatingRequestProcessor类,需要在Struts的配置文件中,使用DelegatingRequestProcessor代替Struts的RequestProcessor类,并在Spring的配置文件中动作映射对应的Bean,可以很方便的转换而不用修改代码,这种方式的缺点是依赖于Struts的RequestProcessor类。
使用Spring的DelegatingActionProxy类,需要在Struts的配置文件中,定义动作映射的type属性为DelegatingActionProxy而不是类的实际名称,并在Spring的配置文件中定义和Struts配置文件动作映射对应的Bean,这种方式和Struts耦合性最小。
注:三者中,使用Spring的DelegatingActionProxy类来整合Spring和Struts的方式最为强大和灵活。
关于Spring , Struts结合学习。
一、前言
刚刚接触了日本一个项目,用的框架名称是Northland Framework,主要用到以下部分
Struts、Spring、iBATIS、Velocity。Struts、Spring如何结合在一起?
二、Spring提供了三种整合Struts的方法:
使用 Spring 的 ActionSupport 类整合 Structs
使用 Spring 的 DelegatingRequestProcessor 覆盖 Struts 的 RequestProcessor
将 Struts Action 管理委托给 Spring 框架
(参见Get a better handle on Struts actions, with Spring
http://www-128.ibm.com/developerworks/java/library/j-sr2.html?ca=drs-tp4105
对应还有译文:
http://gocom.primeton.com/modules/techresource/article504.htm?utm_campaign=searchengine&utm_source=baidu&utm_medium=jjpm&utm_term=Spring+Struts)
三、我只关心第三种整合方法:
这种方法通过Spring提供的两个和Struts相关类来实现:org.springframework.web.struts. DelegatingActionProxy,org.springframework.web.struts. ContextLoaderPlugIn。
ContextLoaderPlugIn实现Struts的PlugIn接口,只要在struts-config.xml中有如下配置:
<action path="/searchSubmit">
type="ca.nexcel.books.actions.DelegatingActionProxy"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
ActionServlet装载的时候就可以顺便装载和Spring相关的beans.xml,和beans.xml中相关的一个东西叫做WebApplicationContext , (在Spring里关键就是取得WebApplicationContext,取得这个也就可以用Spring管理业务),在ContextLoaderPlugIn中是这样保存WebApplicationContext:
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
再看DelegatingActionProxy,它继承于Struts的Action,以后struts-config.xml中所有的
Action-mapping都要指向它,只是每个Action-mapping的path不同,将来也是用这个path来区分究竟需要执行beans.xml中的那个类。如下代码:
public ActionForward execute(){
Action delegateAction = getDelegateAction(mapping);
return delegateAction.execute(mapping, form, request, response);
}
这里的delegateAction就是beans.xml中一个相关的类(beans.xml也要求类继承于Struts的Action) 去看看怎么得到delegateAction:
protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
WebApplicationContext wac = getWebApplicationContext(getServlet(),
mapping.getModuleConfig());
String beanName = determineActionBeanName(mapping);
return (Action) wac.getBean(beanName, Action.class);
}
是如何取得WebApplicationContext呢:
wac=(WebApplicationContext)actionServlet.getServletContext().getAttribute( ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX);
SERVLET_CONTEXT_PREFIX 正是 前边提到的ContextLoaderPlugIn中 的attrName。
现在这个原理一目了然,ContextLoaderPlugIn在actionServlet初始化过程中保存
起来留到后面供DelegatingActionProxy用。
四、在另一篇文章中提到在上面的方法中OpenSessionInView Filter不能用
(参照http://wyyhzc.itpub.net/),这个东西我也不熟悉,是不是有不少Spring的东西在这种方式中都不能用呢? 这就说到另一种取得Spring WebApplicationContext的方法:
在web.xml中配置ContextLoaderListener:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/beans.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
对应的beans.xml和前边那个一样,Log4jConfigListener先不用管,去查看相关文档。
Web服务启动的时候,我们去看看ContextLoaderListener作了什么:
WebApplicationContext = createWebApplicationContext(servletContext, parent);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
同样是保存WebApplicationContext,但是key是ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
怎么才能不用ContextLoaderPlugIn而只用ContextLoaderListener?下面我修改
org.springframework.web.struts. DelegatingActionProxy 把它修改成
ca.nexcel.books.actions. DelegatingActionProxy并且修改一下代码:
修改getWebApplicationContext方法
Return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet,
moduleConfig); 换成下边方法
ServletContext sc = actionServlet.getServletContext();
WebApplicationContext wac = null;
wac = WebApplicationContextUtils.getWebApplicationContext(sc);
return wac;
并且在struts-config.xml中将action的type指向自己的
ca.nexcel.books.actions. DelegatingActionProxy,PlugIn删除web.xml加上刚才提到的Listener,启动tomcat运行一切正常。
五、我把northland的配置文件贴出来。
Struts-config.xml:
<action-mappings>
<action
path="/list"
input="/list.jsp"
name="_list"
scope="request"
type="jp.co.nec.hnes.northland.web.struts.FlowAction"
>
<display-name>一覧画面</display-name>
</action>
<action
path="/register"
input="/register.jsp"
name="_register"
scope="request"
type="jp.co.nec.hnes.northland.web.struts.FlowAction"
>
<display-name>登録画面</display-name>
</action>
Web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:flowConfig.xml,
classpath:viewConfig.xml,
classpath:applicationContext.xml,
classpath:applicationContext-extra.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
从中可以看到
其中的jp.co.nec.hnes.northland.web.struts.FlowAction和
ca.nexcel.books.actions. DelegatingActionProxy的功能差不多。
<struts-config>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml" />
</plug-in>
</struts-config>
第一种方法:
通过Struts的plug-in在Struts和Spring之间提供了良好的结合点。通过plug-in我们实现了Spring context的加载,不过仅仅加载Spring context并没有什么实际的意义,还应该经过配置将Struts的Action交给Spring容器进行管理。
<action-mappings>
<action path="/login"
type="org.springframework.web.struts.DelegatingActionProxy"
name="loginForm">
<forward name="success" path="/main.jsp" />
<forward name="failure" path="/login.jsp" />
</action>
在form bean这个节点上与传统的Struts配置没有什么区别,而在Action上面则发生了变化。在传统的action节点上type属性写入action类的完整类名,而和Spring结合后在这点上是使用了Spring提供的DelegatingActionProxy作为action的type属性,DelegatingActionProxy同样是org.apache.struts.action.Action的一个子类,它将把调用请求转交给真正的Action实现。通过这样的方式,Spring获得了Action实例的管理权,它将对Action进行调度,并为Struts提供所需的Action实例。这样,就可以将Action看作是Spring的一个bean,它就可以享受Spring的所有服务,如依赖注入、实例管理、事务管理等。
在applicationContext.xml中相应的配置如下的节点:
<beans>
.......
<bean name="/login" class="net.xiaxin.action.LoginAction"
singleton="false">
<property name="userDAO">
<ref bean="userDAOProxy" />
</property>
</bean>
</beans>
最后这个bean的配置是关键,这个名为“/login”的bean与Struts中的
<action path="/login" ……>
……
</action>节点相对应,这样,Spring Bean Name与Struts Action Path相关联,当Struts加载对应的Action时,DelegatingActionProxy就根据传入的path属性,在Spring Context寻找对应bean,并将其实例返回给Struts。与此同时,还可以看到,"/login" bean 中包含了一个userDAO 引用,Spring 在运行期将根据配置为其提供userDAO 实例,以及围绕userDAO 的事务管理服务。这样一来,对于Struts 开发而言,我们既可以延续Struts 的开发流程,也可以享受Spring 提供的事务管
理服务。而bean 的另外一个属性singleton="false",指明了Action 的实例获取方式为每次重新创建。这也解决了Struts中令人诟病的线程安全问题。
第二种方法:
为了在 struts-config.xml 文件中配置 DelegatingRequestProcessor,你需要重载 <controller> 元素的 “processorClass” 属性。 下面的几行应该放在 <action-mapping> 元素的后面。
<controller>
<set-property property="processorClass"
value="http://www.zhmy.com/org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>
增加这些设置之后,不管你查询任何类型的 Action,Sping都自动在它的context配置文件中寻找。 实际上,你甚至不需要指定类型。下面两个代码片断都可以工作:
<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>
如果你使用 Struts 的 modules 特性,你的 bean 命名必须含有 module 的前缀。 举个例子,如果一个 Action 的定义为 <action path="/user"/>,而且它的 module 前缀为“admin”, 那么它应该对应名为 <bean name="/admin/user"/> 的 bean
如果你在 Struts 应用中使用了 Tiles,你需要配置 <controller> 为 DelegatingTilesRequestProcessor。
如果第二种方法不行,再用第一种方法。
至此,SS组合已经将Struts MVC以及Spring中的Bean管理、事务管理融为一体。如
果算上userDAO 中的Hibernate 部分,我们就获得了一个全面、成熟、高效、自顶而下的
Web 开发框架。
Struts+Spring整合方式
struts与spring整合方式有三种:
方式一:通过Spring的ActionSupport类实现。
方式二:通过Sping的DelegatingRequestProcessor类实现。
方式三:通过Sping的DelegatingActionProxy类实现。
相同点:以上三种方式都需要在struts的配置文件struts-config.xml中注册spring的ContextLoaderPlugIn插件。即:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
</plug-in>
不同点:
使用Spring提供的ActionSupport类,只需要使用Action继承Spring的ActionSupport类,即可实现Spring与struts的整合,使用起来简单方便,但是struts的Action与Spring耦合在一起,并且Struts的Action不在spring的控制之中,这样如果更换别的IOC容器,或想使用Spring的AOP都是比较困难的,而且如果是多个动作放在一个Action中,则这种方式就无能为了了!
使用Spring的DelegatingRequestProcessor类,需要在Struts的配置文件中,使用DelegatingRequestProcessor代替Struts的RequestProcessor类,并在Spring的配置文件中动作映射对应的Bean,可以很方便的转换而不用修改代码,这种方式的缺点是依赖于Struts的RequestProcessor类。
使用Spring的DelegatingActionProxy类,需要在Struts的配置文件中,定义动作映射的type属性为DelegatingActionProxy而不是类的实际名称,并在Spring的配置文件中定义和Struts配置文件动作映射对应的Bean,这种方式和Struts耦合性最小。
注:三者中,使用Spring的DelegatingActionProxy类来整合Spring和Struts的方式最为强大和灵活。
关于Spring , Struts结合学习。
一、前言
刚刚接触了日本一个项目,用的框架名称是Northland Framework,主要用到以下部分
Struts、Spring、iBATIS、Velocity。Struts、Spring如何结合在一起?
二、Spring提供了三种整合Struts的方法:
使用 Spring 的 ActionSupport 类整合 Structs
使用 Spring 的 DelegatingRequestProcessor 覆盖 Struts 的 RequestProcessor
将 Struts Action 管理委托给 Spring 框架
(参见Get a better handle on Struts actions, with Spring
http://www-128.ibm.com/developerworks/java/library/j-sr2.html?ca=drs-tp4105
对应还有译文:
http://gocom.primeton.com/modules/techresource/article504.htm?utm_campaign=searchengine&utm_source=baidu&utm_medium=jjpm&utm_term=Spring+Struts)
三、我只关心第三种整合方法:
这种方法通过Spring提供的两个和Struts相关类来实现:org.springframework.web.struts. DelegatingActionProxy,org.springframework.web.struts. ContextLoaderPlugIn。
ContextLoaderPlugIn实现Struts的PlugIn接口,只要在struts-config.xml中有如下配置:
<action path="/searchSubmit">
type="ca.nexcel.books.actions.DelegatingActionProxy"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>
ActionServlet装载的时候就可以顺便装载和Spring相关的beans.xml,和beans.xml中相关的一个东西叫做WebApplicationContext , (在Spring里关键就是取得WebApplicationContext,取得这个也就可以用Spring管理业务),在ContextLoaderPlugIn中是这样保存WebApplicationContext:
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
再看DelegatingActionProxy,它继承于Struts的Action,以后struts-config.xml中所有的
Action-mapping都要指向它,只是每个Action-mapping的path不同,将来也是用这个path来区分究竟需要执行beans.xml中的那个类。如下代码:
public ActionForward execute(){
Action delegateAction = getDelegateAction(mapping);
return delegateAction.execute(mapping, form, request, response);
}
这里的delegateAction就是beans.xml中一个相关的类(beans.xml也要求类继承于Struts的Action) 去看看怎么得到delegateAction:
protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
WebApplicationContext wac = getWebApplicationContext(getServlet(),
mapping.getModuleConfig());
String beanName = determineActionBeanName(mapping);
return (Action) wac.getBean(beanName, Action.class);
}
是如何取得WebApplicationContext呢:
wac=(WebApplicationContext)actionServlet.getServletContext().getAttribute( ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX);
SERVLET_CONTEXT_PREFIX 正是 前边提到的ContextLoaderPlugIn中 的attrName。
现在这个原理一目了然,ContextLoaderPlugIn在actionServlet初始化过程中保存
起来留到后面供DelegatingActionProxy用。
四、在另一篇文章中提到在上面的方法中OpenSessionInView Filter不能用
(参照http://wyyhzc.itpub.net/),这个东西我也不熟悉,是不是有不少Spring的东西在这种方式中都不能用呢? 这就说到另一种取得Spring WebApplicationContext的方法:
在web.xml中配置ContextLoaderListener:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/beans.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
对应的beans.xml和前边那个一样,Log4jConfigListener先不用管,去查看相关文档。
Web服务启动的时候,我们去看看ContextLoaderListener作了什么:
WebApplicationContext = createWebApplicationContext(servletContext, parent);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
同样是保存WebApplicationContext,但是key是ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
怎么才能不用ContextLoaderPlugIn而只用ContextLoaderListener?下面我修改
org.springframework.web.struts. DelegatingActionProxy 把它修改成
ca.nexcel.books.actions. DelegatingActionProxy并且修改一下代码:
修改getWebApplicationContext方法
Return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet,
moduleConfig); 换成下边方法
ServletContext sc = actionServlet.getServletContext();
WebApplicationContext wac = null;
wac = WebApplicationContextUtils.getWebApplicationContext(sc);
return wac;
并且在struts-config.xml中将action的type指向自己的
ca.nexcel.books.actions. DelegatingActionProxy,PlugIn删除web.xml加上刚才提到的Listener,启动tomcat运行一切正常。
五、我把northland的配置文件贴出来。
Struts-config.xml:
<action-mappings>
<action
path="/list"
input="/list.jsp"
name="_list"
scope="request"
type="jp.co.nec.hnes.northland.web.struts.FlowAction"
>
<display-name>一覧画面</display-name>
</action>
<action
path="/register"
input="/register.jsp"
name="_register"
scope="request"
type="jp.co.nec.hnes.northland.web.struts.FlowAction"
>
<display-name>登録画面</display-name>
</action>
Web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:flowConfig.xml,
classpath:viewConfig.xml,
classpath:applicationContext.xml,
classpath:applicationContext-extra.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
从中可以看到
其中的jp.co.nec.hnes.northland.web.struts.FlowAction和
ca.nexcel.books.actions. DelegatingActionProxy的功能差不多。