Struts in Spring

来源:互联网 发布:前妻难宠凌慕枫叶知秋 编辑:程序博客网 时间:2024/05/18 05:04

                                                   Struts in Spring
勿庸置疑,Struts是目前Java Web MVC框架中不争的王者。经过长达五年的发展,Struts
已经逐渐成长为一个稳定、成熟的框架,并且占有了MVC框架中最大的市场份额。
长达五年的设计延续性,自然导致其在某些技术特性上已经落后于新兴的MVC框架。
面对Spring MVC、Webwork2 这些设计更精密,扩展性更强的框架,Struts受到了前所未有
的挑战。
不过,纵然目前讨伐之声日起,甚至包括Spring Framework的作者Rod Johnson对Struts
的评价也不甚高。但站在产品开发的角度而言,Struts仍然是最稳妥的选择。
何谓“最稳妥”?并非完全意味着技术上的稳定性,而是指社会劳动力供给。感兴趣的
读者可以去51job、chinahr 这些人力资源网站上搜索一下Java Web 程序员应聘简历。几乎
所有Java Web 开发人员都在简历上注明“精通Struts”,且不论真正精通的能有多少,但就
凭Struts这非凡的上镜率,其普及度也可见一斑。
这也就意味着,即使公司发生惨绝人寰的人事大变动,产品经理也不必过于惊惶失措,
茫茫人海中,有大批的Struts们以供选择,只需好好考虑好新员工的业务培训如何开展即可,
而对于技术延续性,则不必太过于担心。
这也就是Struts 带来的战略性优势(对于公司而言,这一点往往是关键所在),其他
MVC框架目前还无法在这点上与之并驾齐驱。
考虑到目前市面上已经有了众多的Struts书籍8。这里也就不再针对Struts的技术细节再
加赘述,下面主要针对Struts-Spring组合应用进行探讨。

首先,Struts与Spring如何整合?

为了在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>

Spring在设计时就充分考虑到了与Struts的协同工作,通过内置的Struts Plug-in在两者
之间提供了良好的结合点,这与WS组合不同,WS组合需要嵌入来自第三方的类库。
通过plug-in我们实现了Spring Context的加载,不过仅仅加载Context并没有什么实际
意义,我们还需要修改配置,将Struts Action交给Spring容器进行管理:
下面的struts-config.xml 中包含了用户登录示例的相关配置:

<struts-config>
<form-beans>
<form-bean name="loginForm" type="net.xiaxin.bean.LoginForm" />
</form-beans>
<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>
<!-- Struts Action Setting
<action path="/login" type="net.xiaxin.action.LoginAction"
name="loginForm">
<forward name="success" path="/main.jsp" />
<forward name="failure" path="/login.jsp" />
</action>
-->
</action-mappings>
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn"><set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml" />
</plug-in>
</struts-config>
可以看到,其中配置了一个form bean “LoginForm”,在这点上,配置与传统Struts配置
并没有什么不同。
而在action配置上,则出现了一些变化,上面的action-mapping配置中包含了loginForm
的两种配置形式,第一种是面向SS组合改造后的形式,第二种(作为注释)是与之对应的
传统Struts配置方式。
不难看出,我们试图在action-mapping 中增加一个名为loginForm 的Action,传统方式
中,直接将类名作为action节点的type属性,Struts将根据type中的类名加载对应的Action
实例。
而在面向SS组合的配置方式中,我们用Spring提供的DelegatingActionProxy 作为Action
的type属性。DelegatingActionProxy同样是org.apache.struts.action.Action的一个子类,它将
把调用请求转交给真正的Action实现。下面是DelegatingActionProxy的execute方法代码:

 public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//获得实际的Action实例,并将请求转交
Action delegateAction = getDelegateAction(mapping);
return delegateAction.execute(mapping, form, request, response);
}

如此一来,Struts 在运行期加载的实际上是DelegatingActionProxy , 而
DelegatingActionProxy则实现了针对实际Action的调用代理,Struts最终调用的将是由Spring
管理的Action实例。
SS 组合的玄机也正在与此,通过这样的方式,Spring 获得了对Action 实例的管理权,
它将对Action进行调度,并为Struts提供所需的Action实例。既然Action已经由Spring全
权接管,那么我们就可以将此Action看作是Spring中的一个Bean,它可享受Spring提供的
所有服务(依赖注入、实例管理、事务管理等)。
与之对应,Spring Context配置如下:
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"><beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.gjt.mm.mysql.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/sample</value>
</property>
<property name="username">
<value>sysadmin</value>
</property>
<property name="password">
<value>security</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean"
>
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>net/xiaxin/db/entity/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
net.sf.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property></bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionMana
ger">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.db.dao.UserDAOImp">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.TransactionPro
xyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<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(参见Spring 中org.springframework.web.struts.DelegatingActionUtils.
determineActionBeanName 方法的实现代码,DelegatingActionProxy将调用此方法获得Struts
Action对应的Bean name)。
与此同时,还可以看到,"/login" bean 中包含了一个userDAO 引用,Spring 在运行
期将根据配置为其提供userDAO 实例,以及围绕userDAO 的事务管理服务。这样一来,对
于Struts 开发而言,我们既可以延续Struts 的开发流程,也可以享受Spring 提供的事务管
理服务。
而bean 的另外一个属性singleton="false",指明了Action 的实例获取方式为每次
重新创建。这也解决了Struts中令人诟病的线程安全问题(Struts中,由一个Action实例处
理所有的请求,这就导致了类公用资源在并发请求中的线程同步问题。)
至此,SS组合已经将Struts MVC以及Spring中的Bean管理、事务管理融为一体。如
果算上userDAO 中的Hibernate 部分,我们就获得了一个全面、成熟、高效、自顶而下的
Web 开发框架。

 

原创粉丝点击