Struts+Spring+Hibernate配置及应用

来源:互联网 发布:0信誉淘宝店铺 在哪买 编辑:程序博客网 时间:2024/06/08 16:42

1前言

Struts,Spring和Hibernate是目前JAVA企业级开发最流行的开源框架,俗称为SSH框架。本文旨在介绍如何将三个框架整合起来,以满足企业级开发应用。

本框架采用的版本:Struts: 1.2Spring:2.5.5Hibernate:3.3.1

2体系架构

2.1 SSH层

 

图1 集成ssh框架系统架构图

从上图可见,我们的系统架构分成了四层:表示层、业务逻辑层、数据持久层、域模型层。

2.2包分析

在软件架构设计中,软件的层用包来描述,层之间的关系表现为包之间的关系。因此我们将系统划分为如下几个包:

 

 

图2 包结构图

上图中显示的包和层之间的对应关系如下:

接口包

实现包

表现层

 

cn.ittrain.myproject.action

业务逻辑层

cn.ittrain.myproject.service

cn.ittrain.myproject.service.impl

数据持久层

cn.ittrain.myprojject.dao

cn.ittrain.myprojject.dao.impl

域模型层

 

cn.ittrain.myproject.domain

对业务逻辑层和数据持久层,为什么要分别有接口包和实现包?我们先来弄清楚所谓的依赖关系。如果A层调用B层的功能,那么我们说A层依赖于B层。反过来如果B层也调用A层的功能,那么我们说B层依赖于A层。可以想象,如果AB层互相依赖的话,那么我们的程序将是强耦合的,即各个部分关联在一起,牵一发而动全身,显然是很糟糕的设计。因此在软件设计中,我们一般将层设计为单向依赖。A层依赖于B层,但B层不依赖于A层。由于层和包有对应关系,因此包和包之间也存在着类似的依赖关系。在图2中,包的依赖关系是通过虚线箭头来表示的,箭头所在包为被依赖包。

在业务逻辑层,我们定义了两个包:service和service.impl。从图中可以看出,action包依赖与service包,但不依赖于service.impl包,这在传统的架构中是不可能的。service包中是接口,service.impl包中是service包中接口的实现,action包不依赖于service.impl包,就意味着不会调用其中的类的方法,这显然是不可能的。而之所以可能是因为Spring的存在,service.impl包中的对象由Spring容器生成并注入到action包中的对象中,因此action包可以不依赖于service.impl包,而只是依赖于service接口包。如果我们修改service.impl包中的实现,action包不受影响。可见Spring依赖注入的思想极大地松散了我们的程序结构。

2.3对象分析

我们已经知道了包之间的依赖关系。但我们还要弄清楚包中的类和它所依赖的包中的类之间的关系。下图显示了包中的对象之间的关联关系以及多重性关系。

                   

图3 系统对象关系图

一个Action对象(即Action包中产生的对象)依赖于一个Service对象(Service对象是由Spring注入的bean)。一个Service对象依赖于多个DAO对象(DAO对象是由Spring注入的bean)。

一个Action、Service和DAO对象依赖于多个Domain对象。所以我们在做项目的时候应该将复杂的业务逻辑封装在Service中。下图是一个典型的对象调用的例子:

 

 

图4 系统对象协作图

上图中的数字表示对象调用顺序。图中一个Action对象调用一个Service对象,一个Servvice对象调用两个DAO对象:DAO1和DAO2。DAO1和DAO2分别调用Domain对象。

3配置Spring

3.1在MyEclipse配置Spring

1.       生成Web工程。

2.       选中工程,点击右键,弹出菜单,选择MyEclipse->Add Spring Capabilities

3.       根据向导选定Spring的版本。

4.       生成Spring的缺省配置文件applicationContext.xml,该文件缺省生成在src目录下,也可以修改成其它目录,如目录WEB-INF。

3.2更新Spring的库

在MyEclipse中配置好Spring后,MyEclipse将把Spring的库拷贝到工程中。在MyEclipse提供的Spring库是按模块区分的,我们可以将最新的Spring 2.5.5的库整合后替代MyEclipse提供的库,下面的四个库文件基本上涵盖了所有Spring的功能。

spring-2.5.5.jar

aspectjrt-1.6.0.jar

aspectweaver-1.6.0.jar

spring-webmvc-struts-2.5.5.jar

3.3配置Spring容器监听器

在web应用程序中,Spring容器不会自动生成,而必须由web服务器通过web监听器来生成。该监听器读取Spring配置文件,然后生成Spring容器。监听器的配置如下:

<listener>  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

因为监听器是通过WebApplicationContext去读取配置文件applicationContext.xml,因此配置文件应该存放在WEB-INF目录下。如果配置文件存放在其它目录,例如存放在src目录下,那么应该在web.xml文件中指定配置文件的存放路径。

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>classpath*:applicationContext.xml</param-value>

  </context-param>

3.4生成多个Spring配置文件

在实际应用中为了实现分层管理,我们可以将Spring的配置文件切分为多个(将applicationContext.xml复制然后改名即可)。例如我们生成了四个配置文件:

配置文件名

存放路径

作用

applicationContext-common.xml

WEB-INF

SessionFactory,Transaction

applicaitonContext-action.xml

WEB-INF

Struts action bean

applicationContext-service.xml

WEB-INF

Service bean

applicationContext-dao.xml

WEB-INF

DAO bean

将配置文件切分为四个的目的是为了使我们的程序更加清晰。

但是,生成上面的多个配置文件后,Spring不再能够识别它的配置文件,这是应该在web.xml中增加以下元素以告诉监听器查找并识别Spring的配置文件:

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>/WEB-INF/applicationContext-*.xml</param-value>

</context-param>

3.5修改.springBeans文件配置

在.springBeans中增加以下配置:

<configs>

                  <config>WebRoot/WEB-INF/applicationContext-common.xml</config>

                  <config>WebRoot/WEB-INF/applicationContext-action.xml</config>

                  <config>WebRoot/WEB-INF/applicationContext-service.xml</config>

                  <config>WebRoot/WEB-INF/applicationContext-dao.xml</config>

         </configs>

然后刷新工程。

4配置Struts

4.1为工程增加Struts框架

选中工程,点击右键,弹出菜单,选择MyEclipse->Add Struts Capabilities。

4.2 Spring容器生成Action bean

Struts 1.2的action对象是由Struts框架生成的,现在我们将action交由Spring容器来生成。

1.       在struts-config.xml文件中,增加以下元素:

<controller>

    <set-property value="org.springframework.web.struts.DelegatingRequestProcessor"

    property="processorClass"/>

 </controller>

2.       通过struts 向导生成action后,在struts-config.xml文件中会自动添加以下元素:

<action-mappings >

    <action path="/student" type="test.StudentAction" />

  </action-mappings>

3.       在applicationContext-action.xml中配置相应的Action bean:

 

<bean name ="/student"

    class="cn.ittrain.myproject.action.StudentAction"/>

每当生成一个action后,都必须在application-action.xml文件中增加一个bean的配置。

5配置Hibernate

5.1增加Hibernate框架

选中工程,点击右键,弹出菜单,选择MyEclipse->Add Hibernate Capabilities。

l  在Define Hibernate and Spring configuration details界面,

选定用于配置session factory的配置文件,从列表框中选取application-common.xml。

输入SessionFactory Id: sessionFactory

l  在Specify Hibernate database connection details界面选定Use JNDI DataSource。

DataSource:jdbc/mysql

Username:root

Password:root

Dialect:MySQL

l  在Define SessionFactory properties界面,不要在Create SessionFactory Class前面打勾,即不要创建SessionFactory Class。

6 Hibernate反向工程

1.       生成POJO类

数据库中的表对应于POJO类,表中的列对应与类中的属性,表中的一条记录对应一个对象,表之间的关系对应于类之间的关系。

Hibernate Tool为每个POJO类生成一个抽象类,该抽象类中包括了和表中的列对应的字段,而具体类从抽象类继承以方便于我们对POJO类进行扩展。当我们修改了表中的字段重新生成POJO类时,此时Hibernate Tool只更新抽象类而不会更改具体类,因此我们所做的扩展不会丢失。

POJO类及其映射文件放置到cn.ittrain.myproject.domain包中。

2.       生成Hibernate映射文件并更新Hibernate配置文件

Hibernate Tool 为每个表创建一个和POJO类对象的映射文件,并将此映射文件添加到Hibernate的配置文件中。

3.       生成DAO类。

7配置Spring事务管理

7.1 什么是事务

事务可以保证在数据库上完整地执行一系列操作。事务代表一个工作单元,其中的工作要么全部完成,要么回滚到事务开始之前的一致状态。

事务的ACID属性:

l  原子性(Atomicity)

l  一致性(Consistency)

l  隔离性(Isolation)

l  可持续性(Durability)

7.2 Spring事务管理

Spring支持两种事务管理即编程的事务管理声明的事务管理。编程的事务管理可以使我们精确地控制事务的边界,而声明的事务管理可以使我们的业务代码与事务管理代码解耦。我们的框架采用声明的事务管理。

 

Spring接管Hibernate的事务,事务配置在service层。

由图3我们可以知道,一个Service对象可能调用多个DAO对象。例如,Service对象调用DAO1删除一个对象,而调用DAO2保存一个对象。这两个操作在Service中构成一个事务。

1.       配置SessionFactory

<bean id="sessionFactory"class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

<property name="configLocation" value="classpath:hibernate.cfg.xml"/>

</bean>

2.       配置事务管理器

Spring并不直接管理事务。它通过提供一系列的事务管理器将事务管理的责任委托给JTA或者持久化机制所提供的平台相关的事务实现。由于我们的框架使用Hibernate实现持久化,因此我们选择Spring提供的事务管理器org.springframework.orm.hibernate3.HibernateTransactionManager。为此,必须在配置文件中声明HibernateTransactionManager bean:

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

</bean> 

HibernateTransactionManager将事务管理的责任委托给从Hibernate session中获取的 org.hibernate.Transaction对象。当事务成功完成时,HibernateTransactionManager将调用Transaction对象的commit()方法。同样,当事务失败时,将调用Transaction对象的rollback()方法。

3.   事务属性

Spring对声明的事务管理的支持是通过Spring的AOP框架来实现的。事务就是一个方面(Aspect),它用事务边界包装了一个方法,从而使该方法在事务中执行。

事务属性描述事务策略如何应用到一个方法。事务属性包括5个方面:

l  传播行为(Propagation behavior)

传播行为通过调用方(客户)和被调用的方法,从而定义事务的边界。

在图5中,method-A开始一个事务,然后调用Bean-2的method-B。当method-B 执行时,它是在method-A 启动的事务上下文中运行,还是在一个新的事务中运行呢?答案取决于method-B的事务传播行为属性。

 

图5 事务的边界

Spring定义了如下7中传播行为:

传播行为

说明

PROPAGATION_MANDATORY

方法必须在事务中运行。如果没有事务,抛出异常。

PROPAGATION_NESTED

如果一个事务已经存在,那么方法应该在嵌套事务中运行。嵌套事务可以分别提交和回滚。如果不支持嵌套事务,那么就退化为ROPAGATION_REQUIRED。很多供应商不支持这种属性。

PROPAGATION_NEVER

方法不应该在事务中运行。如果有事务存在,将抛出异常。

PROPAGATION_NOT_SUPPORTED

方法不应该在事务中运行。如果有事务存在,那么当前方法在执行过程中事务将被挂起。

PROPAGATION_REQUIRED

方法必须在事务中运行。如果已经有一个事务在运行,那么该方法在该事务中运行。如果没有事务,那么将启动一个新的事务。

PROPAGATION_REQUIRES_NEW

方法必须在它自己的事务中运行。因此将启动一个新的事务。如果当前已经有了一个事务,那么该事务在该方法的执行过程中将被挂起。

PROPAGATION_SUPPORTS

方法不需要事务,但是如果已经有一个事务,那么该方法可以在该事务中运行。

 

l  隔离级别(Isolation levels)

隔离级别定义了一个事务被其它并行事务的行为所影响的程度。

隔离级别

说明

ISOLATION_DEFAULT

数据存储的缺省隔离级别

ISOLATION_READ_UNCOMMITTED

允许读取未提交的数据。可导致脏读(dirty reads),幽灵读(phantom reads)和不可重复读(nonrepeatable reads)。

ISOLATION_READ_COMMITTED

允许读取提交的数据。可阻止脏读(dirty reads),但幽灵读(phantom reads)和不可重复读(nonrepeatable reads)仍可发生。

ISOLATION_REPEATABLE_READ

多次读取统一字段的结果相同(除非当前事务自己做了更改)。可阻止脏读(dirty reads)和不可重复读(nonrepeatable reads),但幽灵读(phantom reads)仍可发生。

ISOLATION_SERIALIZABLE

阻止脏读(dirty reads)、不可重复读(nonrepeatable reads)和幽灵读(phantom reads)。

隔离级别的效率从上至下逐渐降低。

l  Read-only

它只对启动一个新事务的方法有效。

事务对数据只有读取操作。设置read-only属性,可以使数据存储机制进行一些优化工作。Read-only属性将使Hibernate将flush模式设为flush_never,从而避免对象和数据库的同步直到事务结束。

l  Transaction timeout

它只对启动一个新事务的方法有效。

避免事务长时间占用资源,或者事务死锁。如果事务在指定的时间内没有完成,那么该事务将会自动回滚。

l  Rollback rules

定义事务在什么异常发生时回滚,在什么异常发生时不回滚。缺省地,事务只在运行时异常发生时回滚,而当检查异常发生时,事务不发生回滚。

通过Rollback rules可以定义当指定的检查异常或者运行时异常发生时,事务回滚。也可以定义事务在特定的异常发生时不回滚,即使是运行时异常。

4.   声明事务

l  在applicationContext-common.xml中导入aop和tx命名空间。

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

     xmlns="http://www.springframework.org/schema/beans"

     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.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd ">

</beans>

l  配置advice和事务属性。

Spring通过AOP来配置事务管理器,然后Spring将事务编织到Service的方法中。因此根据AOP的原理,我们必须提供advice和pointcut,这样才能形成一个aspect。Advice定义Aspect要做什么,而pointcut则定义将advice编织到哪些方法中去。下面的advice定义了一个事务管理器以及事务的属性。

<tx:advice id=”txAdvice” transaction-manager=”txManager”>

<tx:attributes>

        <tx:method name=”save*” propagation=”SUPPORTS” />

        <tx:method name=”*” propagation=”SUPPORTS” read-only=”true”/>

    </tx:attributes>

</tx:advice>

事务的属性说明:

l   propagation

l   read-only

l   isolation

l   timeout

l   rollback-for

l   no-rollback-for

l  配置advisor。Advisor即时aspect,它由pointcut和advice构成。下面的xml元素首先定义了一个pointcut,然后使用pointcut和上面已定义好的advice,定义了一个advisor。

<aop:config>

<aop:pointcut expression="execution(* cn.ittrain.service.*.*(..))" id="txPointcut"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

</aop:config>    

必须首先导入aop命名空间。

原创粉丝点击