JakartaStruts是Apache软件组织提供的一个开源项目它为Java Web应用提供了基于ModelViewController的MVC框架尤其适用于开发大型可扩展的Web应用尽管基于Java的MVC框架层出不穷事实上Spring的MVC模型也提供了驱动应用系统Web层的能力但JakartaStruts仍然是所有这些框架中的佼佼者
Spring是一个轻量级(大小和系统开支的角度)的IoC和AOP容器它力图简化JEE开发即JEE without EJB而且作为帮助企业级开发的核心支柱Spring为模型层(OR持久层:HibernateJDOiBatis等)服务层(EJBJNDIWebService)以及表现层(StrutsJSFVelocity)都提供了良好的支持和集成方案
首先我们来看一个SpringStruts整合应用下的控制器Action类源代码
public class CourceAction extends Action
{
private CourceService courceService;
public ActionForward execute( ActionMapping mapping ActionForm form HttpServletRequest request HttpServletResponse response) throws Exception
{ Set allCources = courceServicegetAllCources(); //the other statements requestsetAttribute("cources" allCources);
return mappingfindForward("jspView");
}
}
分析:CourceService为一个业务实现的接口此接口声明了一系列的业务处理方法该方法的实现配置为Spring上下问的一个Bean由此看来我们大家都可能会产生一个疑问:Struts action如何取得一个包含在Spring上下文中的Bean呢?为了回答这个问题Spring提供了两种与Struts集成的方式:
()从一个知晓Spring上下文的基类派生我们自己的Struts Action类然后在派生类中就可以使用superXX()方法来获得一个对Spring受控Bean的引用
()将请求委托给作为Spring Bean管理的Struts Action来处理
注册Spring插件:为了使Struts Action能够访问由Spring管理的Bean我们就必须要注册一个知道Spring应用上下文的Struts插件可以在strutsconfigxml中通过如下的方式来完成注册
< plugin classname="orgspringframeworkwebstrutsContextLoadPlugin">
< setproperty value="WEBINF/Yhcipxml" property="contextConfigLocation"> < /PLUGIN>
ContextLoadPlugin()负责装载一个Spring应用上下文(具体的说:是一个WebApplicationContext)value属性值为要加载的配置Spring受控Bean的xml文件的URI
完成第一种集成方案:实现一个知晓Spring的Action基类
这种集成方案是从一个公共的能够访问Spring应用上下文的基类中派生所有的Struts Action但值得庆幸的是:我们不用自己去编写这个知晓Spring应用上下文的基类因为Spring已经提供了orgspringframeworkwebstrutsActionSupport:一个orgapachestrutsactionAction的抽象实现它重载了setServlet()方法以从ContextLoaderPlugin中获取WebapplicationContext因此任何时候我们只需要调用supergetBean()方法即可获得一Spring上下文中的一个Bean的引用
我们再来看一段Action源代码:
public class CourceAction extends ActionSupport
{
public ActionForward execute(
ActionMapping mapping ActionForm form HttpServletRequest request HttpServletResponse response) throws Exception
{ //取得Spring上下文 ApplicationContext context = supergetWebApplicationContext();
//取得CourceService Bean CourseService courseService = (CourseService) contextgetBean("courseService");
Set allCources = courceServicegetAllCources();
requestsetAttribute("cources" allCources);
//the other statements return mappingfindForward("jspView"); }}
分析:这个Action类由ActionSupport派生当CourceAction需要一个Spring受控Bean时:它首先调用基类的getWebApplicationContext()方法以取得一个Spring应用上下文的引用;接着它调用getBean()方法来获取由Spring管理的courceService Bean的一个引用
小结
至此我们已经用第一种方案圆满的完成了Spring与Struts的集成工作这种集成方式的好处在于直观简洁容易上手除了需要从ActionSupport中派生以及需要从应用上下文中获取Bean之外其他都与在非Spring的Struts中编写和配置Action的方法相似但这种集成方案也有不利的一面最为显着的是:我们的Action类将直接使用Spring提供的特定类这样会使我们的Struts Action(即控制层)的代码与Spring紧密耦合在一起这是我们不情愿看到的另外Action类也负责查找由Spring管理的Bean这违背了反向控制(IoC)的原则
实现第二种集成方案:代理和委托Action
这种集成方案要求我们编写一个Struts Action但它只不过是一个包含在Spring应用上下文中的真正Struts Action的一个代理该代理Action从Struts插件ContextLoaderPlugIn中获取应用上下文从中查找真正的Struts Action然后将处理委托给真正的Struts Action这个方法的幽雅之处在于:只有代理action才会包含Spring特定的处理真正的Action可以作为orgapachestrutsAction的子类来编写
下面我们来看一段在之中集成方式下的Struts Action源代码:
public class CourceAction extends Action
{ private CourceService courceService; public ActionForward execute( ActionMapping mapping ActionForm form HttpServletRequest request HttpServletResponse response) throws Exception
{ Set allCources = courceServicegetAllCources();
requestsetAttribute("cources" allCources); //the other statements return mappingfindForward("jspView");
} /* 注入CourceService */
public void setCourceService(CourceService courceService)
{ thiscourceService = courceService;
}
}
分析:大家可以看到在这种方式之下我们的Struts Action类和Spring是低耦合的它仅仅依赖了Spring提供的反向控制(IoC)机制把CourceService注入到了我们的Action中到此大家肯定会有一个疑问:那就是Spring到底是如何提供IoC反向控制的呢?回答这个问题我们需要完成两个步骤的配置:
()在strutsconfigxml中注册Struts Action但要注意的是我们在这里注册的是代理Action幸运的是我们不必亲自编写这个类因为Spring已经通过orgspringframeworkwebstrutsDelegatingActionProxy提供了这个代理的Action具体的配置方法如下:
< action type="orgspringframeworkwebstrutsDelegatingActionProxy" path="/listCourses">
()将真正的Struts Action作为一个Spring Bean并在Spring上下文配置文件中作为一个Bean注册之并将Action所要引用的courceService注入给它
< bean class="comeRedCIPwebCourceAction" name="/listCourses"> < property name=""> < ref bean="courseService"> < /property> < /bean>
注意:name属性的值是非常重要的它必须和strutsconfigxml中的path属性完全一致这是因为DelegatingActionProxy会使用path属性值在Spring上下文中查找真正的Action使用DelegatingActionProxy的好处在于我们可以不使用任何Spring特定的类来编写Struts Action同时Struts动作能够利用IoC取得和他合作的对象唯一不足之处就是不太直观配置相对复杂为了使action委托显得更为直观一些我们可对这种集成方案做进一步的改进:使用请求委托
使用请求委托
为了使action委托看上去更为直观一些Spring提供了DelegatingRequestProcessor另一种专门用于Spring的请求处理器需要在strutsconfigxml中做如下配置:
< controller processorclass="orgspringframeworkwebstrutsDelegatingRequestProcessor">
这样DelegatingRequestProcessor将告诉Struts自动将动作请求委托给Spring上下文中的Action来处理这使得我们可以在strutsconfigxml中用struts action的真正类型来声明它们例如:
< action type="comeRedCIPwebCourceAction" path="/listCourses">
当接受到一个针对/listCourses的请求时DelegatingRequestProcessor会自动从Spring上下文配置文件中查找一个名为/listCourses的Bean(实为一个Struts Action)类
< action type="comeRedCIPwebCourceAction" path="/listCourses">