Struts2.1.6+Spring2.5.6+Hibernate3.3.1全诠注实例详解(一)(转载)
开发环境
JDK1.6.0_18
Eclipse3.2.1
MyEclipse5.1.0
Tomcat6.0.10
MySQL5.0.27
Navicat Lite for MySQL 8.1.20
每个人的开发环境可能会有差异,但有一点我需要说明的是,
JDK
的版本不得低于
1.5
,因为用到了很多
1.5
版才支持的新特性。
Tomcat
和
MySQL
请
不要低于我所用的版本,因为我没在其它的版本上进行测试。
Navicat
则是
MySQL
数据库的图形化操作工具。我在这里假定各位目前已经设置好了开发环境,下面就开始详细的说明。
由于要阐述的内容比较多,大象决定将它们划分成个几章节来讲,这一章就主要来说说
jar
包的选择。
第一部分
:
选择必须的
jar
包
新建一个
web
项目,然后将必要的
jar
包
COPY
到
lib
里面。根据本文实例
demo
,大象给出下图中的最少
jar
包配置。
我对这些
jar
包进行一下说明,方便大家理解。
解压
Struts2.1.6
的
lib
文件夹,从中选出上面
7
个
jar
包添加到我们的工程库中。
commons-logging
、
freemarker
、
ognl
、
struts2-core
、
xwork
这
5
个还是
struts2
的核心包。但在
Struts2.1.6
这个版本中,还需要加上
commons-fileupload
包。如果没有,则启动就会报错,不过不需要像网上传言的那样还得加上
commons-io
的
jar
包,这些大象都亲自做过测试。在本实例中,我将对
struts2
也采取注解的方式,所以用到了
struts2-convention-plugin-2.1.6.jar
这个插件。因为要与
spring
整合,所以
struts2-spring-plugin-2.1.6.jar
也必不可少。
大象在这里偷个懒,直接将
spring
的完整
jar
包加了进来,如果各位想精简类库的话,就选取它的分类
jar
包吧。比如本例使用
struts2
作为
MVC
框架,所以
spring
的
webmvc
就不可能用到了。有想改的朋友请自己动手改下。另外有点我想说下,如果采取完整
spring
的
jar
包,还需要
Spring2.5.6\lib\
concurrent
文件夹中的
backport-util-concurrent.jar
,如果不加这个,
spring
会报错。但是采取
spring
分类
jar
包的形式,这个可以不用加,至于具体使用什么需要依赖这个包,大象还没去测试过,这个有待验证。还有
lib\
slf4j
下的日志包,目前很多都开始采用基于
slf4j
接口的日志器,它的好处就是日志器是根据
slf4j
的接口来进行实现,可以在不改变代码的情况下更换日志器。最后
Spring
的源代码中使用的是
commons-logging
记录日志,因此这个包不能少,不过因为
struts2
也用到了,所以这里就省了。
Hibernate
从
3.3
版开始,对
jar
包结构做了一次大的调整,我们只需要加入
lib\required
文件夹下面的
6
个
jar
包。请注意这
6
个
jar
包都是使用
Hibernate所
必须的。另外再加上
hibernate
核心包。这里我将
slf4j-api-1.5.2.jar
换成了
1.5.0
,这是因为
slf4j
是一个通用日志
接口,不提供任何实现,我在
demo
里面使用的是
log4j
,而
hibernate
包里面没有
log4j
的
slf4j
实现。而且如果版本不一致,会有异常,因此我就采用
Spring2.5.6\lib\slf4j
里面提供的配套版本。另外我将
commons-collections-3.1.jar
换成了
Struts2.1.6
里面的
3.2
版。
例子中使用
Hibernate JPA
来完成实体对象映射,所以上面这些包都必不可少。使用注解的方式,可以不用写繁琐的配置文件,降低了出错机率。而且现在很多人都喜欢这种方式。大家可以去
sourceforge
下载。
下载地址
:
http://sourceforge.net/projects/hibernate/files/
本例使用
DBCP
连接池来管理数据源。
MySQL
数据库的连接驱动。
这个包的作用是创建动态代理对象。比如在使用
AOP
方式管理
spring
事务时,如果我们的目标对象没有实现接口,而又要使用
AOP
来处理事务,这时就需要用到这个
jar
包。可以在
Spring2.5.6\lib\cglib
里面找到。
JSTL
标签库,很经典的东东,如果需要可以将它们加入
lib
中。
大象在这里建议大家做开发的时候,不要过多的依赖
MyEclipse
提供的那些功能,多用手动的方式来做。那样方便是方便了,但不利于学习。比如加入上面这些开发所用的类库,这样可以更清楚的了解每个
jar
包的作用,增加知识的积累,方便以后调试。
Ok
,关于这部分的内容到这里就说完了,那么,我们下次继续。
实例中涉及的配置文件有这么几个
applicationContext.xml
jdbc.properties
log4j.properties
struts.xml
web.xml
我准备在本章中只讲
applicationContext.xml
、
jdbc.properties
和
web.xml
。
log4j
的配置大同小异而且也不在本文范围。至于
struts.xml
我准备留到后面与
Action
代码一起来讲,因为用的是
struts2-convention-plugin
插件来实现
struts2
的注解,所以这两个结合起来讲要好一些。
第二部分:分析配置文件
1
、
jdbc.properties
本例采用
MySQL
数据库,所以我设置了一个属性文件,用来存放一些连接信息和
Hibernate
相关的设置。
因为我们使用的是
Hibernate
来与数据库进行交互,把这些东西写在单独的文件里,是方便修改,如果你想换成
SQL Server
或是
Oracle
,只需要更改
driver
、
url
以及
dialect
,而且还可以*控制
sql
语句的显示的开关,非常方便。至于写在这里怎么用呢?请接着看下面的
applicationContext.xml
说明。
2
、
applicationContext.xml
这个文件就是
spring
的主配置文件了,当然,本例也只有这么一个
spring
的配置文件,内容不多,但做的工作还是很多的,下面我给大家详细分析一下。
我把这两部分放在一起是因为这两者是相互联系的,而且也比较好说明。可以这样来理解,
PropertyPlaceholderConfigurer
这个类就是读取
jdbc.
properties
文件,并将它们设置到这个类的属性中。然后再将下面数据源配置中定义的这些
${jdbc.driver}
、
${jdbc.url}
字符串换成属性文件中相同名称的值。
${}
这种写法,是类里面方法解析用的,网上都说这是叫占位符,我看了源代码的,其实是把它们当成字符串截取前后的特殊字符,再根据里面定义的名称找属性文件中对应的值。所以这个类只能读取
properties
格式的文件,你如果还有其它需要加入的属性文件,可以在
list
之间加入,写在
value
标签里面。
根据
base-package
指定的路径,扫描其下所有包含注解的
Bean
,并自动注入。比如
@Repository
,
@Service
这些都是注解,前者表示持久层,后者表示业务层。
这可是非常非常好的一个功能,是从
Spring2.5
开始加入的一个非常棒的特性。有了它,我们将不用再去写那繁琐的
<bean id="" class="" />。本文的主旨就是全注解,就是为了告诉大家不用写配置文件(当然不是绝对不写)来怎样进行开发工作。关于这部分的具体情况,在后面代码章节中会详细讲解。
这就是在
Spring
中定义
Hibernate
相关的配置,
Spring
已经集成了这部分功能。通过
class
里面定义的类名称我们很容易就能理解,这是使用注解的方式映射实体以及创建
Hiberante SessionFactory
。
${hibernate.dialect}
、
${hibernate.show_sql}
和上面的数据源配置获取方式一样,当
applicationContext.xml
定义好之后,就不用再对它进行修改,而是将修改对象变成了
jdbc.properties
文件。
另外在
Spring2.5.6
版中,加入了一个很有用的小功能,就是
packagesToScan
属性,它是根据
value
中定义的路径来扫描其下所有的注解实体类。大象对这个路径做了多种测试,另外又看了源代码,发现它只能匹配某一类型的路径,而不是所有路径。比如上面的
value
值表示,扫描
entity
包下面的所有包中的注解类,如果你将类直接放在
entity
包下,那么服务器启动和程序运行时都不会报错,但是当你的代码需要用到这个类的时候,就会出现异常,提示你找不到实体。
这是事务定义,而且是使用注解方式定义事务
(
@Transactional
),
proxy-target-class
=
"true"
表示采用动态代理类来管理事务,如果是
false
表示采用接口代理来管理事务(默认值为
false
)。什么意思呢?就是说对于需要加入事务处理的类,如果是实现接口,那么将采用
Spring
的默认事务管理(
Spring
默认方式为接口),如果不采用接口,而直接使用类,那么就需要
cglib
类库的支持,它通过动态的创建目标类(就是你需要加入事务的类)的子类,然后对这子类中的方法(当然是从目标类中继承来的)进行事务管理。这其实就是
AOP
切面,而且从中可以看出来,需要加入事务的方法不能为
private
、
static
、
final
的方法。这样说也不是很严格,说它不能加入事务,是说它不能主动的启动一个事务,如果某个
private
方法是被某个
public
方法调用的,而
public
方法是可以被动态代理加入事务的,所以这个
private
方法也一样被加入了事务,只是它处在
public
方法的事务之中。但是
static
和
final
这两类方法因为不能被子类覆盖,所以无法加入事务。如果这两类型的方法不被其它的事务方法所调用,那么它们就会以无事务的方式运行,因此很容易造成隐患,这一点请大家特别注意。
上面这个就是使用配置式来定义事务,两种方式的区别主要是,注解式只用写那么一句话,然后在业务类或方法中加入
@Transactional
这个注解标记,就完成事务声明,不过对于每个业务类都需要在类或方法中加入这些标记。而配置式声明,就是不用加这些标记,只要你的方法名称命名比较统一,就可以像上面这样定义事务规范,然后在
aop
标签中定义切入点与执行通知就行了。我感觉如果业务逻辑不是太复杂的情况,配置式会比较简单,而且修改起来也方便,这两种方式我都写出来了,至于用哪一种,由你们自己决定。
3
、
web.xml
现在使用的
Servlet
容器还是
2.4
版,因此
web.xml
里面还是需要写配置文件的,到了
3.0
版就可以采取注解的方式来实现了。
Spring ApplicationContext
配置文件的路径
,
可使用通配符
,
applicationContext*.xml
表示所有以
applicationContext
开头的
xml
文件。
多个路径用
,
号分隔。比如可以这样写:
不过推荐采用通配符的写法,能够简单点,为什么还要弄那么复杂呢?
context-param
是在容器启动后最先被执行的,并且被放入到容器上下文中。在这里引入
spring
的配置文件,是供
Spring
的
ContextLoaderListener
监听器使用。而这个监听器中会有一个
ContextLoade
类用来获取这个配置文件中的信息。从而进行
Spring
容器的初始化工作。
因为是采用注解的方式来进行开发,所以
spring
的配置文件其实只有一个,上面那个星号可以去掉。
这个监听器就是为了读取
Spring
的配置文件,这在上面已经讲到了。
这是
Spring
提供的一个用来防止内存泄漏的监听器。在我们使用
struts2
框架,或其它的某些类库时,因为它们自身的设计,会用到
Introspector
(内省)机制来获取
Bean
对象的信息。但不幸的是,这些框架或类库在
分析完一个类之后却没有将它从内存中清除掉,内存中还保留有大量的静态资源,而这些东西又无法进行垃圾回收,因此产生了很严重的内存泄漏问题。直接表现为服务器的内存使用会随着时间而不断上升,最后的结果当然就是服务器当掉。所以在这里加入此监听器,能够
帮助我们更好的处理内存资源回收的问题。
这是
Spring
的编码过滤器,我们可以直接拿来用,相信这段配置应该很好理解,不过请大家注意
forceEncoding
这个参数,把它设置为
true
表示不管请求中的编码是什么格式,都将强制采用
encoding
中设置的编码方式。另外对于响应也将按照
encoding
指定的编码进行设置。另外不建议将编码设置成
gb2312
或是
gbk
格式,请采用基于
Unicode
的
UTF-8
编码。
这个过滤器是个好东西,有了它,我们在使用
Hibernate
延迟加载的时候,就不会再为因
Session
被关闭,导致延迟加载数据异常而头痛了。网上有很多人说这个不好,其实在使用中,效果还是不错的。
首先我要说这个过滤器的名字很雷,不知道写这类的家伙是不是个变态,或者喜欢恶搞。主要原因就是,这个过滤器的功能是推迟清理值栈中的值,
以便在
web
层
中进行访问,另外就是为了配合
SiteMesh
装饰器进行工作(官方中的说明)。如果不加这个,那么
Struts2
的默认过滤器就会清空值栈中的值,这样就会导致异常。所以说这类的名字和功能完全不搭边,很容易让人产生误解。
在
2.1.6
版本里面,已经用这个过滤器取代了以前的
FilterDispatcher
,而且在
api
文档中已经标注为
@deprecated
(不赞成)
,并说明是从
Struts 2.1.3
版开始就弃用这个过滤器了,改用
StrutsPrepareAndExecuteFilter
,除此之外,还可以选择
StrutsPrepareFilter
和
StrutsExecuteFilter
。不过大象建议大家还是选择
StrutsPrepareAndExecuteFilter
吧,这也是官方推荐的。
web.xml
里面的几个重要的配置就这些,不过不要忘了,给这些
filter
加上
filter-mapping
映射。还有一点,请注意这些过滤器的顺序,这个顺序是很重要的,程序运行时,是根据这些
filter-mapping
的排列顺序依次执行过滤操作的。如果不想出现莫名其妙的错误,请控制好这些过滤器映射的顺序。
我会在最后一章附上源码,大家就这样慢慢看吧。看到最后一章的时候,可能这些相关的知识就比较清楚了。到时再对照源码练习下,应该会有一些收获。恩,这部分就到此结束了,我们下次继续。