`
tianhandigeng
  • 浏览: 368706 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Struts2.1.6+Spring2.5.6+Hibernate3.3.1全注解实例详解(一)(转载)

阅读更多

JavaEE 企业级开发中,以 SSH2 框架为核心的应用非常广,大象根据项目实践经验,通过一个实例,详细的为大家讲解如何实现全注解式的开发。
    开发环境
    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 ,关于这部分的内容到这里就说完了,那么,我们下次继续。

在上一章中详细分析了 JAR 包的选择,那么这次我将对例子中的一些必须的配置文件进行下说明。虽然这些配置在网上也很容易找到,但是很多都没有讲个因为所以出来,这样根本就得不到提高。在此,大象为各位详细分析一下这些内容。
    实例中涉及的配置文件有这么几个
     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 的排列顺序依次执行过滤操作的。如果不想出现莫名其妙的错误,请控制好这些过滤器映射的顺序。
    我会在最后一章附上源码,大家就这样慢慢看吧。看到最后一章的时候,可能这些相关的知识就比较清楚了。到时再对照源码练习下,应该会有一些收获。恩,这部分就到此结束了,我们下次继续。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics