Spring + Hibernate 是用 POJO 实现JavaEE 轻量级架构在数据持久层和业务层使用的主流模式. POJO 是指 Plain Old Java Object,即"普通Java对象". 轻量级架构可以这样理解, 它使用了诸如Spring,Hibernate,iBATIS等轻量级框架来开发企业级应用, 相对于传统的EJB(2.0及以前)重量级架构, 轻量级架构实现更容易,而且"无侵入",或者说没有侵略性,即使用轻量级框架时非常方便,并可以自由地选择使用其全部或部分功能,另外也很容易在原有框架的基础上进行扩展. 关于使用POJO 轻量级架构的详细信息请参阅<<POJOs IN ACTION>>一书. 此书中文版翻译得也不错, 链接地址为:
http://www.china-pub.com/computers/common/info.asp?id=34697.
这里我举一个简单的Spring + Hibernate 的示例, 我是用MyEclipse开发的, 而且使用了Spring对Hibernate封装后的API来间接操作数据库.关于Spring 和 Hibernate, 以下两本书很适合入门时阅读:
精通Hibernate:Java对象持久化技术详解
http://www.china-pub.com/computers/common/info.asp?id=24485(这本书讲得不是最新的3.x版本的,但影响不大)
Spring 2.0核心技术与最佳实践
http://www.china-pub.com/computers/common/info.asp?id=34820
由于我使用的是英文版的Eclipse, 我按照做的步骤依序记下了简单的英文表示,如下所示: (英文可能不太规范,就当伪代码来读哈~~ )
整个项目工程的下载链接为:
http://www.blogjava.net/Files/cooky/HSpring.rar.
注意,由于上传文件大小有限制,我删除了用到的所有第三方开发包(jar),如果你想直接运行此项目则需先将使用到的jar包copy到HSpring/WebRoot/WEB-INF/lib 文件夹下. 另外你可以跟着我上面的英文步骤和下面的详细介绍在MyEclipse自动导入包.
jar包的列表如下,如果提示缺少某些jar,可参考下图进行导入:
整个项目工程的包视图(Package Explorer)如下:
下面我对前面的英文步骤做一些说明,你可以跟着下面的步骤来做,同时参加前面的英文信息.
1.新建一个网站项目, 名字为 HSpring, 选择 Java EE 5.0 版本.
2.新建一个类User, 作为我们的实体bean(这里是指POJO,不是EJB里的实体bean). 指定包名为 test.hspring.model (此处为方便间接创建包,其实应该先设计包结构再建类)
3.在User.java 编码, 先写四个属性:id,name,password,sex 和默认构造函数.bean 的定义包含默认构造函数和属性的getter,setter方法,所以下面添加这四个属性的访问方法.直接按快捷键Alt+Shift+S 选Generate Getters and Setters...然后选择全部属性(为它们生成方法).此快捷键建议记住.你也可以右击代码然后选择Source->Generate Getters and Setters....
另外注意,我们将让数据库自动生动主键,即以自动增长的方式实现代理主键(代理主键指主键不包含逻辑含义).所以把setId()方法设为private以防止用户修改id.还有,对于boolean型的属性如sex, isSex() 和 getSex() 都可以作为此属性的getter方法.
User.java 的源代码如下:
4.现在我们要加入Hibernate的内容.右击项目名HSpring,选择MyEclipse->Add Hibernate Capabilities...,选择3.1版本的核心包,并选择"copy checked..."选项以把用到的Hibernate jar包copy到HSpring/WebRoot/WEB-INF/lib文件夹下,这样你的项目移动时依然可用,不会因为build-path的不一致而需要重新导入包(如果你只是自己演示用,可以选择只加入build-path).
下一步中选择生成新的hibernate.cfg.xml文件,位于src文件夹下.这是使用Hibernate时默认指定的配置文件.然后选择数据库连接,如果你已经在MyEclipse配置过你的数据库(这里我用的是MySQL 5.0),则可以选择配置好的数据库连接.否则的话可以取消此项的勾选,稍后在文件中手动配置. 下面一步是问你是否自动生成一个用于访问Hibernate API的sessionFactory类.由于这里我会用到Spring包装后的API,所以不选中此项.
5.第4步中的xml文件生成后,以配置视图打开该文件(默认情况下已经这样打开了).现在先在这个文件中配置数据库连接.选择使用JDBC驱动,在URL项填jdbc:mysql://localhost:3306/HSDB,当然端口(3306)和数据库名(HSDB)你可以根据自己的情况自行指定.由于我们后面会在此数据库中新建USERS表,所以确保现在这个数据库中没有此表(不区分大小写).否则将会覆盖此表造成数据丢失.(当然你也可以在下面的步骤里重新指定表的名称而不用USERS,稍后会讲到)
现在要指定数据库连接用到的驱动类,在这之前,先把MySQL的连接驱动包copy到lib文件夹下(你可以到MySQL官方下载,名称类似mysql-connector-java-5.0.5-bin.jar).然后指定驱动类为com.mysql.jdbc.Driver. 接着设置用户名(默认主用户为root)和密码(比如我的MySQL访问密码是admin).最后选择数据库方言为MySQL.
可能的hibernate.cfg.xml类似:
注意,里面最后设置的<mapping />指向第6步中生成的配置文件,此文件用来定义如果把User类映射到数据库表.另外,我额外添加了三个属性:show_sql一般在调试时使用,即在控制台显示程序执行的sql语句;format_sql用来格式化前面的sql语句,否则每条(比如插入)语句都占一行很不直观;最后的hbm2ddl.auto属性设为create,用来配置由数据库映射文件(如第6步中生成的文件Us
er.hbm.xml)生成数据库表的定义(ddl),并且执行此ddl(即创建表的sql语句)来自动生成表,这样就不用手动在数据库创建表了.由此更可见Hibernate强大的ORM(Object Relational Mapping,对象关系映射)能力.hbm2ddl是基于ant运行的开放工具,由于MyEclipse集成了ant,运用更方便.但使用ant也是J2EE 开发人员必备的能力之一.
自动生成数据库表可作为测试用,但我在这里是专门用它来生成表,此表以后就可以使用了,不是为了测试.所以执行一次程序并生成了表后,就要把这个属性删除,否则每次执行都会重新建表并覆盖原来的表了.下面还会详讲.
6.现在我们就可以新建配置文件,来为User类指定如何映射到数据库.在test.hspring.model包(或称文件夹)下新建xml文件User.hbm.xml(你也可以建在其他地方).文件的文件头<!DOCTYPE>定义了此xml文件的语法,如果你忘记了文件头的格式,可以去你添加的hibernate3.jar包里找位于最后的两个dtd文件,分别是cfg.xml和 hbm.xml两种hibernate配置文件的语法格式,注释内容中有文件头示例(或参照下面的代码).
User.hbm.xml文件内容如下:
文件中的一个<class>标签将对应一个实体bean类,这里只有一个:User. <class>标签的name属性指定要映射的实体bean类; table属性指定要映射的表名,不设置此属性的话将默认采取类的名称(如User).类的属性用<property>子标签来说明,但用来映射主键的属性(如id)要用用专门的<id>标签标识.<property>的name属性和实体bean类里的属性对应(名称相同); column属性指定此属性将映射到表中的哪一列(字段),不设的话默认和name相同.另外<property>还有not-null,length属性等,都是故名思义.<id>有个子属性:<generator>,用来指定主键的生成方式,为auto_increment时表示采用Hibernate自己实现的增长机制,为native时表示将采用底层数据库自己的实现机制,所以移植性更好.关于映射的更多信息请参阅Hibernate的相关内容.
7.现在要把写好的User.hbm.xml加入hibernate.cfg.xml中.在配置视图下打开hibernate.cfg.xml,点Mappings区域的Add...,找到User.hbm.xml并选择.第5步中的hibernate.cfg.xml内容已经实现加入了User.hbm.xml.
8.Hibernate的配置告一段落,现在来进行和Spring相关的操作.右击项目名选择MyEclipse->Add Spring Capabilities...,在出来的对话框中,选择Spring版本为:Spring 2.0,勾选 MyEclipse Libraries 选项,在列出的jar包里,选择 Spring 2.0 AOP Libraries, Spring 2.0 Core Libraries, Spring 2.0 Persistence Core Libraries,同样选中最下面的选项把包copy进项目(或者只加入build-path).然后选择新建Spring bean 配置文件.下面可以按照默认选项,来生成一个引用已有的Hibernate配置文件的sessionFactory来供Spring使用.
9.下面我们来实现DAO(Data Access Object,数据访问对象)的操作.由于Spring鼓励面向接口编程,所以虽然我们的项目很简单,还是使用了接口.新建接口(Interface) UserDAO, 位于test.hspring.dao 包下.此接口定义了通过Hibernate访问数据库的一系列操作,用来为服务(Service)提供方法,而面向表现层的服务是不能直接调用Hibernate(或Srping)的API来实现这些方法的.以下是其源码:
10.现在编写实现了以上接口的类(如 UserDAOImpl).在这里我把这个类扩展(继承)了Spring包里的HibernateDAOSupport类,这样可以加入Spring提供的事务管理,并通过Spring封装了Hibernate API后的方法来间接进行数据库操作(对类的对象进行操作,Hibernate将操作映射到数据库).这些方法常用的有HibernateTemplate.get(long id), save(class,long id), update(Object), find(String),load()等等.HibernateTemplate对象可由父类中提供的this.getHibernateTemplate()方法得到.以下是UserDAOImpl类的源代码:
11.现在,Hibernate+Spring的内容基本完成,就缺少和表现层交互的内容了.不过,前面提过要运行一次程序以自动生成数据库表,所以这里我提供了一个类:RunThisOnce,位于test.hspring包.它把一个User对象保存对数据库.源码如下:
在运行之前,要在applicationContext.xml文件中配置要使用的bean: userDAO.这里我们用Spring事务及AOP(Aspect Oriented Programming,面向切面编程)机制来管理bean.配置后的applicationContext.xml内容如下:
bean 的proxyTargetClass属性设为true,是因为得到bean里可能会抛出ClassCastException,这样就需要指明此bean为代理bean.其他配置一目了然,userDAO这个代理bean用target属性指明实际代理的类.关于此处配置的详细信息(如设置方法中事务的传播机制等),请参阅Spring 相关内容.
运行RunThisOnce之前,你还需要开启MySQL服务,并创建在hibernate.cfg.xml中指定的数据库(如HSDB).但USERS表不用创建.现在,在RunThisOnce.java的代码中右击,选择 Run As->Java Application, 运行成功后会在数据库生成USERS表,而且里面有一条记录(name为"cooky").
正如前面所说,我运行此程序只为了自动生成数据库,所以,现在去hibernate.cfg.xml把<property name="hbm2ddl.auto">create</property>删除,以防止程序每次运行都重新建立表.而且RunThisOnce.java也应该删除.如果现在再次运行此程序你只会向表中添加name,password和sex都相同的一条新记录(之前没有设这三个之中的任一个的unique为true,即允许重复).
Okay...终于写完了~~
那么,表现层(如网页浏览器)怎么和现在的Spring+Hibernate框架进行交互呢(即实现服务/Service)? 你可能想到在Servlet中像RunThisOnce.java中那样得到applicationContext.xml配置的bean,并调用dao的方法.但是,这样是极不规范的.Spring配置的bean不能随便获取.我会再写一篇关于JSF与Spring结合的文章来简单探讨这个问题.
另外,我还会写一篇关于JUnit单元测试的文章,也会用到现在的这个项目HSpring.
Keep It Simple, Stupid