S2SH框架的集成 20131130
代码下载 : 链接: http://pan.baidu.com/s/1sz6cQ 密码: 513t
这一个星期的时间里,学习SSH框架技术,首先因为之前的项目用到了Spring的IoC,所以先学习的是Spring框架,IoC和AOP是其中最为核心的思想;因为学习过MyBatis持久层框架技术,所以继续学习的框架就是Hibernate,这个框架上就是Model和映射文件之间的技术还有就是配置文件,配置文件的内容有两个部分:连接数据库的配置信息和映射文件的信息;最后学习的就是最纠结的Struts2框架技术,之前就是被他卡住了,今天也因为配置包,耗费了好几个小时,他最重要的思想就是Action处理请求,再根据处理过程的结果,调用对应的视图返回给客户端。同时有一个发现:学习Spring和Hibernate都是使用在Java项目中的,而学习Struts2是Web项目,不知道为什么。。。
自己先回顾一下三个框架的知识
首先是Spring,这里使用的是Spring3.6版本的,貌似官方网站改动太大了,也不提供下载了。Spring最核心的就是IoC和AOP。IoC或者是DI,依赖注入或者称作是反转控制技术,这些是利用SpringFramework中的ApplicationContext,加载Spring的配置文件applicationContext.xml,其中这个配置文件就是类之间的依赖关系,降低了类之间的耦合程度,以装载Bean的形式,由Spring的IoC容器负责初始化和维护它们之间的依赖关系。
Spring中另外一个核心思想就是AOP,面相切面编程的理念。他整个软件系统分成了两个部分:核心业务逻辑和横切关注点。OOP的编程思想是从静态的角度思考软件系统的架构设计,而AOP的思想则是站在动态的角度思考软件系统的运行过程。在Spring中还学习了Spring的事物管理机制。而且这种事物管理机制也是基于AOP机制的,利用AOP将其中的方法作为事物去处理。当然还有基于Annotation实现的事务机制。这些事务的概念主要用于对于数据库的写操作,保证数据的一致性。
Hibernate采用的是hibernate3,基本配置方式就配置文件和映射文件。映射文件主要是在将Model层和数据库中的Table对应起来,而配置文件就是配置连接数据库的信息,同时将映射文件集成在配置文件中。Hibernate查询方式主要是HQL和QBC:HQL依赖于Query接口,比较强大;QBC依赖Criteria接口,是比较规范化的查询API,而是是面相对象的查询。同时在Hibernate中还有事务管理的机制,不过不是他本身实现的,而是依赖于底层的JTA或者是JDBC实现的。使用Configuration加载配置文件,使用Session对持久化对象进行操作。
Struts2刚刚学完,拦截器、Action控制器和Result配置为核心,配置文件首先是在web.xml中加载Struts拦截器,对于结尾是.action的请求同意使用Struts2进行拦截处理。然后请求道对应的Action处理请求,之后根据result返回对应的视图。然后就是最为核心的配置文件struts.xml,这里面对应者所有的Action,ActionClass和result对应的视图关系。
这就是一个星期的收获。但是三个框架之间的学习是相互独立的,那么如何将三个框架集成在一起,Spring集成Hibernate比较容易,将Spring中访问数据库中的部分使用Hibernate,替换掉之前的Template即可,同时Spring的IoC机制可以控制类之间的依赖关系。结合在Web项目中,拦截器的思想实现AOP思想,或者是Spring的AOP也是非常优秀的。
这一节,学习框架的整合技术:Struts2和Spring集成的原理和步骤、Hibernate和Spring集成的原理和步骤、S2SH框架的集成方式。
1.Spring集成Struts2
理论上Struts2可以和任何框架集成,因为Struts2提供了一种插件机制,可以进行灵活的扩展。通过各种插件,Struts2 可以与任何的JavaEE框架整合,Struts2框架提供了针对Spring的插件。
1.1整合原理
Struts2和Spring集成需要使用Spring的插件包struts2-spring-plugin.jar,这个是和struts2一起发布的,Spring插件会覆盖Struts2的ObjectFactory接口,从而改变Struts2创建Action实例的方式。创建一个Action实例,该插件就会使用Struts2配置文件中对应的Action的class属性去和Spring配置文件中的Beanid属性进行匹配,如果找到,则使用Spring创建的对象;否则使用Struts2自身创建,然后使用Spring装配。Struts2和Spring集成之后,处理用户请求的Action不是Struts2框架创建的,而是Spring插件创建的。创建实例的时候,配置Action时指定的class属性值不再是类名,而是Spring中配置文件中的bean的id,Spring会根据此id从Spring容器中获得对应的实例。
1.2集成步骤
1.添加集成插件类库
因为Struts2中对应有spring的包,所以使用和Struts2一起发布的Spring包,包括核心的Struts2基础包和所以包中的和Spring相关的,最重要的就是struts2-spring-plugin.jar,在这个包中有一个配置文件是struts-plugin.xml。Struts2应用启动的时候就会加载这个配置文件,该配置文件让struts2中的Action由SpringIoC容器进行委托管理,Struts2中的Action于Sping中的IoC容器中的Bean自动装配,完成Struts2和Spring的整合。
我们查看一下这个配置文件struts-plugin.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />
<!-- Make the Spring object factory the automatic default -->
<constant name="struts.objectFactory" value="spring" />
<constant name="struts.class.reloading.watchList" value="" />
<constant name="struts.class.reloading.acceptClasses" value="" />
<constant name="struts.class.reloading.reloadConfig" value="false" />
<package name="spring-default">
<interceptors>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
</interceptors>
</package>
</struts>
struts.objectFactory常量是spring,从而使Struts2框架使用Spring容器提供Action的实例。
2.配置applicationContext.xml文件
把Struts2和Spring框架进行集成的时候,通常需要让Struts2中的Action由Spring IoC 容器进行委托管理,修改RegAction的配置,改成由Spring创建,然后用Struts2调用的方式,从而使用Struts2于Spring框架集成的方式完成用户注册。
在applicationContext.xml配置该bean
<!-- Struts2 Action 配置 -->
<bean id="reg" class="com.yang.s2s.action.RegAction" scope="prototype"/>
3.配置struts.xml文件
修改struts.xml配置中的Action的class属性,将其调用改成SpringIoC容器中提供的Action的实例。
<package name="reg" extends="struts-default" namespace=”/user”>
<action name="reg" class="reg">
<result name="success">/user/reg_success.jsp</result>
<result name="input">/user/reg.jsp</result>
</action>
</package>
其中配置一个reg的Action, class属性值是reg,那么Struts2 框架将在Spring配置文件中查找一个id为reg的Bean。当请求url为 /user/reg.action的时候,Struts2就会在SpringIoC容器中获取RegBean的实例,来响应用户端的请求。此外在SpringIoC配置中,bean的属性值是scope=”prototype”,对于每一次请求都会生成一个新的Bean实例来响应客户端。
4.配置web.xml
Web项目需要加载Spring的配置文件等等,之前我们做的项目,都是在Java项目中,使用的是ApplicationContext类加载Spring的配置文件,但是对于Web项目,则使用的是在web.xml中加载框架,同时也许加载Struts2框架。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" id="WebApp_ID"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:web="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- 配置Spring框架的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- Spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
上述的配置文件,通过初始化参数contextConfigLocation指定Spring的配置文件的位置,然后配置了ContextLoaderListener监听器来启动Spring。Spring框架可以从WEB-INF文件夹下或者是类路径下加载配置文件。默认情况之下,Spring配置文件名是applicationContext.xml,该文件可以保存在classpath或者是WEB-INF目录下面,实际上Spring可以有多个配置文件,那么使用这一种方式配置:
<context-param>
<param-name>contextConfigLocation</parm-name>
<param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</prama-value>
</context-param>
这种方式表示的是WEB-INF目录下面以applicationContext-开头的xml文件盒classPath目录下的applicationContext-开头的xml是Spring的配置文件。
备注加载JAR包:
首先是struts基础包:all common jar in Struts2 、 freemarket.jar、ognl.jar,struts2-core.jar, xwork-core.jar
然后是该struts2中对应的Spring包:spring-aop.jar, springasm.jar, spring-beans.jar, spring-context.jar, spring-core.jar, spring-expression.jar,spring-test.jar, spring-web.jar
然后就是在Struts2中的struts2-spring-plugin.jar,这个包在spring中也是有的,但是没有发现有struts-plugin.xml配置文件,所以选择的是Struts2中的JAR包
但是我们运行程序的时候发现出现bug,还记的我们在学习Spring的时候,因为同样的配置spring包,也是运行出错,之后添加了aopalliance.jar aspectjrt.jar, aspectjweaver.jar就正常运行了,这里也是。
2.Spring集成Hibernate
Spring框架为了集成各种ORM框架提供了全面的支持,其中针对Hibernate框架的支持体现如下:
使用方法Spring配置文件来对Hibernate的SessionFactory进行配置;
使用Spring提供的HibernateTemplate类和HibernateDaoSupport类降低了单纯使用HibernateAPI的复杂程度,并且简化的DAO类的编写;
使用Spring的声明性事务方便的管理Hibernate中的事务
Spring提供了OpenSessionInViewFilter过滤器类,可以解决由于session关闭导致的延迟加载失败的原因。
这里我们将SSH框架集成在一起:
- 添加Hibernate的类库
上一个项目中已经包含了Struts2和Spring的包,这里在添加Hibernate的包即可,Hibernate的JAR包有hibernate3.jar,在加上require中的6个包:antlr.jar, common-collections.jar,dom4j.jar, javaassist.jar, jta.jar, slf4j-api.jar.然后就是自己在添加的缺少的包:mysql-connector.jar,还有slf4j-log4j12.jar,其实还有一个,找了半天才找到错误,自己查看连接的文章吧!
同时因为访问的是数据库,所以还有之前的common-dbcp.jar & common-pool.jar
- 配置SessionFactory
在SSH集成中,SessionFactory对象不再需要开发者使用Java代码加载,而是使用Spring配置文件,从SpringIoC中获取
- 增加依赖注入
配置完SessionFactory之后,根据具体情况把SessionFactory对象注入到相关的DAO中
- 配置声明式事务
在开发过程中,配置声明式事务,可以不再程序中添加事务控制代码,而是使用声明式事务统一管理
- 配置OpenSessionInViewFilter过滤器
由于Hibernate延迟加载的特性,当表示层(JSP)访问被延迟加载的数据可能会导致数据读取失败,通过配置OpenSessionInViewFilter过滤器解决。
1.有一个小小的技巧,因为开发过程中,我们希望可以尽快的找到错误,所有在Spring中的配置容器的时候,在开发阶段建议不要将容器初始化设置成为延迟加载机制 default-lazy-init="false">
2.对于在hibernate中,我们使用的是最新的hibernate3.6,这个版本的Hibernate是依赖于JPA,所以需要导入hibernate-jpa.jar
3.使用HibernateTemplate模板类,使用HibernateTemplate无需实现特定的接口,只要获得一个SessionFactory的引用,就可以进行持久化操作,这样我们可以减少Hibernate的访问复杂的API,使用它统一访问。同时在HibernateTemplate中提供了一种更加灵活的回调方式,通过下面的两个方法完成:
Object execute(HibernateCallback callback);
List executeFind(HibernateCallback callback);
上述两个方法都需要一个HibernateTemplate的实例,HibernateCallback是Spring框架提供的一个接口,包含一个doInHibernate(Session session);该方法只有一个参数就是Hibernate的 Session,通过它来以Hibernate的方式进行操作。
4.使用HibernateDaoSupport,让DAO实现类继承HibernateDaoSupport,通过它获得HibernateTemplate,其中在applicationContext.xml中配置DAO的时候,需要把HibernateDaoSupport的sessionFactory配置Bean对象
3.事务机制(没有配置成功,不知道为什么)
在Spring的applicationContext.xml配置文件中,部署了Action,Bean等组件,并且有容器维护它们之间的依赖关系,还需要配置Hibernate的事务管理,这里我们使用的是Spring的声明式事务。
回顾一下之前的Spring和Hibernate的事务机制:
Hibernate事务机制是使用Session的beginTransaction() trans.commmit()实现,这个是基于JDBC或者是JTA实现的事务,因为Hibernate本身是不具备事务的处理能力。
而在Spring中对于事务的管理支持的非常好:一种是基于配置方式实现的事务机制,这种事务管理机制是基于AOP面相切面编程的思想,同时事务的最小单位是方法。另一种是基于注释方式实现的事务管理。这些事务是通过PlatformTransactionManager接口实现的事务管理机制。
因为在Struts中不建议直接操作Hibernate的Session,而且也不方便,同时Hibernate本身是不支持事务的,而是依赖于底层的JDBC或JTA,所以不建议使用Hibernate的基于Session的事务管理机制。那么我们在这里,建议采用是Spring的事务管理机制,Spring的XML方式或者是注释方式都是可以的,建议使用配置的方式:
<!-- 配置Hibernate的事物管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置事务增强,指定事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 配置详细的事务定义 -->
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="update*"/>
<tx:method name="del*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.yang.s2s.service.*(..))" id="allMethods"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods"/>
</aop:config>
这里使用的是HibernateTransactionManager配置了id为txManager的Hibernate的事务管理器,然后使用Spring中配置Advice的方法对业务中的方法进行了配置,并且制定了他的事务管理器。
关于在实际的应用中什么地方定义事务?
系统的事物管理应负责业务逻辑组件中的业务逻辑方法,只有对业务逻辑方法添加事务管理才会有实际的意义,而对于单个的DAO方法配置事务的管理机制,是没有意义的,所以本章中对于多有的业务逻辑Service中的方法配置事务管理
4.OSIV模式
在实际的开发中,为了获得更好的性能,一般会使用Hibernate的研制加载的功能。但是在分层的Java Web项目中,延迟加载的运用有时会因为使用不当而出现错误。比如通常会在业务逻辑中通过Hibernate获取持久化对象,由于Hibernate使用延迟加载,当需要在业务逻辑层查询持久化对象的属性和它关联的对象的时候,不会填充到这个持久化对象中。业务逻辑层通过Hibernate读取完数据后,会关闭Hibernate的Session对象,转向表示层输出数据,在表示层,不仅要显示持久化对象加载的属性,还可能要显示没有加载的属性和关联对象的属性,因为这个时候Session已经关闭,在程序运行到表示层的时候,就可能抛出异常。
要解决延迟加载导致的问题,有两种方案:一种是不使用延迟加载功能;另一种是使用OSIV(Open Session In View)模式。因为Hibernate的延迟加载可以改善程序的性能呢个,所以一般会使用第二种方案。
OSIV的核心就是控制Session对象在表示层所有的数据(包括要延迟加载的数据)输出结束之后才关闭,这样避免在表示层中读取被延迟加载的数据抛出异常 org.hibernate.LazyInitlizationException.
Spring为此专门提供了一个OpenSessionInViewFilter过滤器,其主要功能是使每一个请求绑定一个Hibernate Session,这样即使最初的事务完成了,也可以在Web层进行延迟加载。
OpenSessionInViewFilter过滤器将Hibernate Session绑定到请求的线程中,他将自动被Spring的事务管理机制探测到。所以OpenSessionInViewFilter特别适合Service层使用HibernateTransactionManager或者是JtaTransactionManager进行事务管理的环境。
说了这么多,如何使用呢?
只需要在web.xml中配置OpenSessionInViewFilter过滤器即可
<!-- 配置OpenSessionInViewFilter -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
完结S2SH框架,其实三个框架单独使用已经不是问题了,怎样结合起来使用,在未来的实际项目中锻炼吧!完结S2SH入门之旅。
YangTengfei
2013.12.01