先放图,本节的工程文件目录结构如下:
其中:
aopalliance.jar
aspectjweaver-1.7.2.jar
可能需要到网上下载。随便百度个就行,蛮多人分享的。
Spring与Hibernate两边结合在一起之后,Spring对Hibernate的一些启动操作进行了接管。毕竟Spring本身是一个管理类工厂的服务,而许多程序、应用的初始化操作,可以交给Spring来完成。
于是,Hibernate里面的数据库地址、用户名、密码和操作参数等,统统交给Spring来接管了,我们无需担心。于是Hibernate.cfg.xml文件变得异常简洁。记得在上一节讲解Hibernate的时候,启动一个服务要写相当多的
启动代码:
然后才是
业务代码
(也就是功能代码):
其实Hibernate只需要启动一次,然后整个项目都用一个或者两个实例就好(
根据线程的负载和锁的情况,别造成这个用了Hibernate,那个急着用又用不上又不能自己生成一个实例来用)
。所以具体怎么管理,怎么生成,或者什么时候用这些类的实例(
Configuration、StandardServiceRegistryB uilder、ServiceRegistry、SessionFactory等等)
就交给Spring框架来决定吧。我们看到,其实最主要的功能,集中在session处。如何保存、如何从数据库获取一行,都要靠session来执行。那么其实把冗余的初始化功能分离后,剩下的东西,写进一个功能模块里面,就成了
DAO
(Data Access Object数据访问对象
)。我们来看这么一段代码:
文件BookDao.java
public interface BookDao{
}
|
可以看到,其实DAO类(或接口)就是一个封装了数据库操作的类(或接口)。DAO意味着封装了非常非常具体的数据库操作后,直接得到的服务。它可以是查询某个id得到这个id下的书名字符串,也可以是新建并保存一个书本条目。我们看到这个类使用了POJO类Book,Book的定义会在后面给出。具体怎么塞到数据库里面的,得由这个类的实现(implements)来进行:
文件BookDaoImpl.java
package dao_service;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import table.book.Book;
@Repository
public class BookDaoImpl implements BookDao{
}
|
从这个BookDaoImpl类实现,我们可以看到内置了一个SessionFactory。细心的同学会发现,有这个private类,却没有具体的实现,也没有setSessionFactory方法来设置它。它在saveBook()方法使用的时候不会是个空指针吗?
奥妙就在这里,其实这个类内实例的导入,是由Spring来完成的。Spring跟Hibernate结合以后,提供了一系列自动化方法,比如可以自动搜索dao_service文件夹(也就是BookDao.java和BookDaoImpl.java存放的文件夹)下的类,根据关键词过滤来判断哪些是类的实现,根据方法名或者内部私有变量的名字,来判断装入何种类的实现(如具体的SessionFactory等等)。
为了验证自动装配这一点,我们给它再套一个壳子,我们新建一个BookService类,里面提供的服务和内容跟BookDao类完全一样:
文件BookService.java
public interface BookService{
}
|
然后我们建立一个实现,同样是在接口名后面加上Impl:
文件BookServiceImpl.java
package dao_service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import table.book.Book;
@Service
public class BookServiceImpl implements BookService
{
}
|
这个壳子啥都没做,仅仅是用了BookDao接口的方法来完成自己的方法。注意,在BookServiceImpl里所使用的不是BookDaoImpl的方法,而是BookDao,说明我们要想使用,必须得有个具体的实现。意味着整个过程必须有人来搞。这个人显然就是Spring。有兴趣的同学可以写一个计数器,看看Spring生成了多少个实例,并且都调用了哪个实例来使用(提示:用静态变量作计数器,则所有实例之间都可以共享了。不懂是否线程安全,为了准确计数,可以考虑加锁)
说了这么多,那么实体类(Entity Class)呢?在这里定义:
文件Book.java
package table.book;
//import org.hibernate.annotations.Entity;这个已经过时,用javax里面的entity代替
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
public class Book implements Serializable {
}
|
可以看到这个Book实体类里面有5个属性,对应着数据库表中5个列:id、bookname、isbn、price、stock。同理,给这个Book.java配置一个文件给hibernate读取:
文件Book.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-3-15 16:30:05 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
</hibernate-mapping>
|
接下来我们看看具体hibernate的配置文件:
文件hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
<!--
-->
<hibernate-configuration>
</hibernate-configuration>
|
明显少了很多东西。这些本该在hibernate.cfg.xml中的配置被转移到了Spring配置文件里面了:
文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
public class MainClass {
}
|
这么多代码写好以后,存储一本新书就非常简单了。首先Spring通过读取configuration里的xml文件得到配置好的context,然后context再通过getBean获取实体类,并用实体类进行数据库操作。我们可以看到多次运行后数据库里面加了很多条目。
具体运行结果,上图: