前言
目前比较流行MVC架构有Struts、Spring MVC、WebWork、JSF,Struts是一个基于Sun J2EE(JavaEE)平台的MVC框架,主要是采用Servlet和JSP技术来实现的,它通过反射机制扩展了java的jsp和Servlet。由于Struts能充分满足应用开发的需求,简单易用,敏捷迅速,在过去一直颇受关注。Spring提供了管理业务对象的一致方法并且鼓励了依赖注入对接口编程而不是对类编程的良好习惯。Spring的架构基础是基于使用JavaBean属性的Inversion of Control(IOC)容器。
所谓的控制反转(Inversion of control)
Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了Hibernate和其他O/R mapping(Ibatis,Toplink,jta,jdo等实现了持久层)解决方案。WebWork、JSF在此就不介绍。
目前比较流行的O/R mapping框架有Hibernate、IBatis,Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装(Ejb中EntityBean对JDBC进行了重量级的封装),使得我们可以随心所欲的使用对象编程思维来操纵关系数据库。
Struts+Spring+Hibernate集成架构图
如何将Struts、Spring、Hibernate集成一起使用,并充分使用他们各自长处呢?接下来我对Struts+Spring+Hibernate集成的分层作分析和如何实现集成Strust+Spring+Hibernate作一下介绍。
从上图知服务器端web应用程序共分五层:表示层(view)、控制层(controller)、业务层(business)、DAO层(Data Access Object)、持久层(persistence)+RMI。每个层在处理程序上都有一项明确的责任,不应该在功能上与其它层混合,并且每个层要与其它层分开的,所以需要设计他们之间通信接口。
从介绍各个层开始,讨论一下这些层担当的任务和各层的功能以及它们的相互关系。
一、表示层(view)
视图是用户看到并与之交互的界面,视图向用户显示相关的数据,并能接收用户的输入数据,但不能进行任何实际的业务处理。视图可以向业务层查询业务状态,但不能改变业务层,视图还可以接受模型发出的数据更新事件,从而对用户界面进行同步更新。视图其实就是一组JSP文件,在这些JSP文件中没有业务逻辑,也没有业务层信息,只有标签,这些标签可以是标准的JSP标签或客户化标签,如Struts标签库中的标签。
由架构图可知,把Struts框架中的ActionForm Bean分到了表示层中,ActionForm Bean也是一种JavaBean,除了具有一些JavaBean的常规方法,还包含一些特殊的方法,用于验证HTML表单数据以及将其属性重新设置为默认值。Struts框架利用ActionForm Bean来进行视图和控制器之间表单数据之间表单数据的传递,如下图所示:
Struts框架把用户输入的表单数据保存在ActionForm Bean中,把它传递给控制器Action,Action可以对ActionForm Bean中数据进行修改,JSP文件使用Struts标签读取修改后的ActionForm Bean中的信息,重新设置HTML表单。
二、控制层
控制层中的控制器Action接受用户的输入并调用业务层的业务方法和表示层的组件去完成用户的需求。当Web用户单击Web页面中的提交按钮来发送HTML表单时,控制器接收请求并调用相应的业务层方法去处理请求,然后调用相应的视图来显示业务层返回的数据。
Struts中的控制器由ActionServlet类和Action类来实现,ActionServlet主要负责接收HTTP请求信息,根据配置文件struts-config.xml的配置信息,把请求转发给适当的Action对象。如果该Action对象不存在,ActionServlet会先创建这个Action对象,Action充当用户请求和业务逻辑处理之间的适配器,其功能是将请求与业务逻辑分开,Action根据用户请求调用相关的业务逻辑组件,业务逻辑由Spring的IoC、AOP、DAO、ORM来完成,Action类侧重于控制应用程序的流程,而不是实现应用程序的逻辑。为了使用Action中使用到Spring受管理JavaBean、IoC、AOP来调用Spring的业务逻辑、事务管理、安全性服务。Spring对Struts提供了这种集成服务,通过org.springframework.web.struts.DelegatingRequestProcessor类充当Action的代理,将Struts Action配置在Spring ApplicationContext中,而且Action不必继承于ActionSuport,每次客户请求Struts Action时,DelegatingRequestProcessor将充当代理的作用,即通过它将Action请求转发给Spring IoC容器进行处理。通过这样的方式,Spring 获得了对Action 实例的管理权,它将对Action进行调度,并为Struts提供所需的Action实例。既然Action已经由Spring全权接管,那么就可以将此Action看作是Spring中的一个Bean,它可享受Spring提供的所有服务(依赖注入、实例管理、事务管理等)。
三、业务层
业务层应该和表示层以及控制层之间保持,在本集成分层框架中,位于上层的表示层和控制层依赖于下层的业务层的实现,而下层业务层不应该依赖于上层的表示层和控制器的实现。业务层提供了处理应用程序的业务逻辑和业务校验,如验证用户登录系统的密码是否正确;提供了管理事务,允许与其它层相互作用的接口,如使用Spring的管理事务Bean和DAO层的DAO接口类(DAO层)以及给Action(控制层)提供业务接口。业务层还提供了管理业务层级别的对象的依赖、管理程序的执行(从业务层到持久层)等。
四、DAO层
DAO提供了访问关系型数据库所需要的所有操作的接口,其中包括创建数据库、定义表、字段和索引,建立表间的关系,更新和查询数据库等,DAO将底层数据(Hibernate持久对象)访问操作和业务层(business层)逻辑分离开,对业务层(business层)提供面向对象的数据访问接口。而业务层(business层)调用DAO接口实现各种业务方法,如验证用户密码是否正确业务方法,并向控制层(Action类)提供调用业务方法的接口。
五、持久层
由集成图可看出,Web应用的另一个末端是持久层Hibernate,Hibernate是一个ORM(O/R Mapping)工具,没有Hibernate时,通常使用JDBC来连接数据库,并利用连接池来改善性能,利用事务服务来保证可靠性,还会利用JNDI(java naming & directory interface)来传递数据源,配合SQL语言来完成数据库的查询操作。但Hibernate可以复杂性的JDBC过程以对象系统映射的方式对开发者透明,将需要经验和技巧的设计部分封装在PO对象和XML映射文件的配置中。使用了Hibernate应用程序就不需发直接面对JDBC代码,由PO对象和Hibernate的API来取代。Hibernate利用hibernate.cfg.xml或hibernate.properties文件来配置Hibernate所使用的包括数据库和连接池等在内的资源,Hibernate利用*.hbm.xml来描述POJO和数据库资源的映射关系。
六、RMI
(Remote Method Invoke)
Spring提供类用于集成各种远程访问技术,对远程访问的支持可以降低在用POJO实现支持远程访问业务时的开发难度。Spring提供了对远程方法调用(RMI)的支持,借助于Spring提供的RmiProxyFactoryBean和RmiServiceExporter可以开发RMI应用。RMI服务器集成了Aglets的运行环境AgletContext,并实现了Agent相关业务方法,由业务层通过RMI的业务接口DAO来完成Agent相关的业务。
七、集成实现
7.1 Spring集成Struts1.x
Struts是基于MVC的,它实现了Model2模型的Web应用框架,Struts框架的核心作用其提供的灵活的控制层,它是基于Java Servlet、JavaBean、ResourceBundle、XML等技术构建的。
Spring对Struts提供了两种集成方式:
1、通过覆盖Struts中的 RequestProcessor
将 Spring 从 Struts 动作中分离是一个更巧妙的设计选择。分离的一种方法是使用 org.springframework.web.struts.DelegatingRequestProcessor 类来覆盖 Struts 的 RequestProcessor 请求处理程序,如配置清单如下:
通过 Spring 的 DelegatingRequestProcessor 对Struts进行整合,在struts-config.xml配置文件中
                                  name="deptForm"       parameter="m"       path="/deptAction"       scope="request"       type="org.itfuture.www.action.DeptAction"       validate="false">                                            
利用了 在 Spring 配置文件中注册一个动作     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">             注意:在 (1) 处,使用名称属性注册了一个 bean,以匹配 struts-config 动作Action映射路径名称。DeptAction 动作揭示了一个 JavaBean 属性,允许 Spring 在运行时填充属性(通过set依赖注入),具体实现如下: 具有 JavaBean 属性的 Struts 动作DeptAction package org.itfuture.www.action; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction; import org.itfuture.www.form.DeptForm; public class DeptAction extends DispatchAction {     private Date date;     public DeptAction()     {         System.out.println("DeptAction()---------");     }     public ActionForward execute(ActionMapping mapping, ActionForm form,             HttpServletRequest request, HttpServletResponse response) {         DeptForm deptForm = (DeptForm) form;         request.setAttribute("now",date);         return mapping.findForward("test");     }     public Date getDate() {         return date;     }     public void setDate(Date date) (1)     {         this.date = date;     } } 如上的代码中,您可以了解到如何创建 Struts 动作。在 (1) 处,我创建了一个 JavaBean 属性。DelegatingRequestProcessor自动地配置这种属性。这种设计使 Struts 动作并不知道它正被 Spring 管理,并且使您能够利用 Sping 的动作管理框架的所有优点。由于您的 Struts 动作注意不到 Spring 的存在,所以您不需要重写您的 Struts 代码就可以使用其他控制反转容器来替换掉 Spring。 DelegatingRequestProcessor 方法的确比第一种方法好,但是仍然存在一些问题。如果您使用一个不同的 RequestProcessor,则需要手动整合 Spring 的 DelegatingRequestProcessor。添加的代码会造成维护的麻烦并且将来会降低您的应用程序的灵活性。此外,还有过一些使用一系列命令来代替 Struts RequestProcessor 的传闻。 这种改变将会对这种解决方法的使用寿命造成负面的影响。 2、将动作管理委托给 Spring 一个更好的解决方法是将 Strut 动作管理委托给 Spring。您可以通过在 struts-config 动作映射中注册一个代理来实现。代理负责在 Spring 环境中查找 Struts 动作。由于动作在 Spring 的控制之下,所以它可以填充动作的 JavaBean 属性,并为应用诸如 Spring 的 AOP 之类的特性带来了可能。具体使用步骤如下: 在struts-config.xml中配置                                   name="empForm"       parameter="method"       path="/empAction"       scope="request"       type="org.springframework.web.struts.DelegatingActionProxy"  (1)       validate="false" >                                        上面是一个典型的 struts-config.xml 文件,只有一个小小的差别。它注册 Spring 代理类的名称,而不是声明动作的类名,如(1)处所示。DelegatingActionProxy 类使用动作映射名称查找 Spring 环境中的动作。这就是我们使用 ContextLoaderPlugIn 声明的环境。    将一个 Struts 动作注册为一个 Spring bean 是非常直观的,如下面所示。我利用动作映射使用  在 Spring 环境中注册一个 Struts 动作     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">                                                                                            动作委托的优点 动作委托解决方法是这三种方法中最好的。Struts 动作不了解 Spring,不对代码作任何改变就可用于非 Spring 应用程序中。RequestProcessor 的改变不会影响它,并且它可以利用 Spring AOP 特性的优点。  动作委托的优点不止如此。一旦让 Spring 控制您的 Struts 动作,您就可以使用 Spring 给动作补充更强的活力。例如,没有 Spring 的话,所有的 Struts 动作都必须是线程安全的。如果您设置  7.2 Spring集成Struts2 1.将struts2-spring-plugin-2.0.8.jar文件放到应用中,放到WEB-INF/lib目录下 在这个插件包中有个struts-plugin.xml文件,它的内容如下:                                                 注意:    这里它将框架常量struts.objectFactory覆盖了,设置为”spring”,其实这里是使用了缩写,我们可以写全称:org.apache.struts2.spring.StrutsSpringObjectFactory。这个缩写的”spring”是和bean配置中的name属性相对应的。默认情况下所有由框架创建的对象都是由ObjectFactory实例化的,ObjectFactory提供了与其它IoC容器如Spring、Pico等集成的方法。 覆盖这个ObjectFactory的类必须继承ObjectFactory类或者它的任何子类,并且要带有一个不带参数的构造方法。在这里我们用org.apache.struts2.spring.StrutsSpringObjectFactory代替了默认的ObjectFactory。 如果action不是使用Spring ObjectFactory创建的话,插件提供了两个来自动装配action,默认情况下框架使用的自动装配策略是name,也就是说框架会去Spring中寻找与action属性名字相同的bean,可选的装配策略还有:type、auto、constructor,我们可以通过常量struts.objectFactory.spring.autoWire来进行设置。 2.利用Spring配置文件来注册对象 在applicationContext-xml.进行配置bean,当配置Action的id时应该与struts.xml中class我相应,进行关联起来。如下:       xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">     3.在Struts2的配置文件中声明逻辑Action时候与Spring中Action相关联     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN“          "http://struts.apache.org/dtds/struts-2.0.dtd">                                                                                                                                  4.配置Struts2分发器和Spring,将Spring 、Struts的jar包放到应用中 在web.xml中加上:                                                      org.springframework.web.context.ContextLoaderListener                                                           7.3 Spring集成Hibernate Hibernate提供了O/R Mapping功能,通过XML配置文件(*.hbm.xml)能够将对象映射到RDBMS,开发Hibernate需要如下内容: Hibernate配置文件。 一般可以通过两种方式进行。 一是提供hibernate.cfg.xml文件,用于创建Hibernate SessionFactory。 二是提供hibernate.properties文件(Hibernate SessionFactory)。 Hibernate映射文件。如Vip.hbm.xml POJO类源文件。如org.itfuture.www.pojo.Order.java Spring对Hibernate的集成提供了定义Hibernate资源、对Hibernate资源的依赖注 入。定义Hibernate资源:可以通过在Spring配置文件中定义sessionFactory是给出Hibernate映射文件的定义。如本系统的sessionFactory定义如下:                                                                                                                Spring DAO Hibernate抽象提供了HibernateTemplate,HibernateTemplate充分利用了Spring IoC特征,从而实现了对Hibernate资源的依赖注入。如果应用只是用Spring IoC,则只需要在Spring配置文件中为它提供sessionFactory。如上配置文件。 (1)、第一种集成方式 第一步:Hibernate配置文件hibernate.cfg.xml           "-//Hibernate/Hibernate Configuration DTD 3.0//EN"           "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">                           org.hibernate.dialect.Oracle9Dialect                                                                              第二步:Spring配置文件applicationContext.xml                                                                                                                                                       第三步:配置Spring,将Spring的相应jar包包含到应用中 在web.xml中加上: ……                            org.springframework.web.context.ContextLoaderListener      …… (2)、第二种集成方式 第一步:在src下配置数据源配置文件jdbc.properties connection.username=wllt connection.password=123456 connection.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl connection.driver_class=oracle.jdbc.driver.OracleDriver hibernate.show_sql=true dialect=org.hibernate.dialect.Oracle9Dialect 第二步:Spring配置文件applicationContext.xml          xmlns:aop="http://www.springframework.org/schema/aop"          xmlns:tx="http://www.springframework.org/schema/tx"          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">                                                                                                                                                                                                                                                                                                                                          ...................    第三步:配置Spring,将Spring的相应jar包包含到应用中 在web.xml中加上: ……                            org.springframework.web.context.ContextLoaderListener      ……下载本文