16.3 实现系统DAO层
Java EE一向以良好的可扩展性吸引着众多行业的青睐,而这种良好的可扩展性就是建立在严格的分层结构之上的。Java EE将所有持久层访问都封装在系统的DAO层,所有的持久化访问都通过系统的DAO组件来实现,避免了业务逻辑组件与持久化访问耦合。
这种模式就是标准的DAO模式,在这种模式下,每个DAO组件都包含了数据库的访问逻辑,可对一个数据库表完成基本的CRUD等操作。
DAO模式的实现至少需要如下3个部分:
DAO工厂类。
DAO接口。
DAO接口的实现类。
DAO模式是一种更符合软件工程学的开发方式,采用DAO模式大致有如下几个理由:
更好的软件复用:DAO模式抽象出了数据访问方式,于是业务逻辑组件无须理会底层的数据库访问,而只专注于业务逻辑的实现。即便系统需要重构,持久化技术需要改变,系统的业务逻辑组件也完全无须任何改变,因为系统的业务逻辑组件并没有任何持久化技术。
更具可维护性:DAO将数据访问集中在独立的一层,所有的数据访问都由DAO对象完成,这层独立的DAO分离了数据访问的实现与其他业务逻辑,将数据访问集中使得系统更具可维护性。
更具可移植性:DAO还有助于提升系统的可移植性。独立的DAO层使得系统能在不同的数据库之间轻易切换,底层的数据库实现对于业务逻辑组件是透明的。数据库移植时仅仅影响DAO层,不同数据库的切换不会影响业务逻辑组件,因此提高了系统的可复用性。
DAO模式下的DAO组件用于完成对应实体的CRUD操作,故都应该提供如下几个方法:
根据主键查找实体,对应根据主键获取指定记录。
保存实体,对应插入一条记录。
修改实体,对应修改一条记录。
根据主键删除,对应删除一条记录。
根据实体删除,对应删除一条记录。
查找全部,对应不带任何where子句的select语句。
除此之外,每个DAO组件还提供数量不等的查询方法,这些查询方法是根据系统业务需求来确定的,并不完全相同。
从上面的介绍可见,标准DAO组件接口的类图大致如图16.10所示。
图16.10 标准DAO组件接口的类图
一旦采用了Spring框架,就可以避免实现系统中的DAO组件工厂,因为Spring容器就是一个最大的工厂,可以管理容器中的所有组件,包括管理系统中的DAO组件。
对于不同的持久层技术,Spring的DAO支持基本一致:提供一个DAO模板,将通用的操作放在模板里完成,而对于特定的操作,通过回调接口完成。Spring的IoC容器就是最大的容器,使用IoC容器就可以避免实现自己的DAO工厂。
Spring为Hibernate提供的DAO支持类是HibernateDaoSupport,该支持类为实现DAO组件提供了两个便捷的方法:
setSessionFactory(SessionFactory sf):该方法可用于依赖注入SessionFactory实例。
getHibernateTemplate():该方法可以很方便地获取HibernateTemplate实例。
获得了Spring的HibernateTemplate实例后,大部分持久化操作都可通过HibernateTemplate实例的一行代码来完成。
16.3.1 DAO的基础配置
与前面的介绍一致的是,HibernateDaoSupport类只需一个SessionFactory属性即可完成数据库访问,实际的数据库访问由模板类HibernateTemplate完成。
前面已经介绍过了,为了将Hibernate的SessionFactory纳入其IoC 容器的管理下,Spring提供了一个LocalSessionFactoryBean类,通过该类,可以将SessionFactory配置成Spring容器中的Bean。配置SessionFactory的配置片段前面已经给出,此处不再赘述。
提示
如果想将Hibernate配置采用传统的Hibernate配置方式,也可以保留hibernate.cfg.xml文件。然后在配置LocalSessionFactoryBean时,通过指定configLocation属性来指定hibernate. cfg.xml配置文件的位置。
16.3.2 实现系统DAO组件
一般说来,DAO接口是最缺乏变化的对象,DAO接口里声明了基本的增加、删除、修改,以及数量不等的查询方法。因此,DAO接口的定义也比较缺乏变化。
本系统中包含了5个实体,这5个实体对应系统的5个DAO组件,这5个DAO组件分别用于操作5个实体,并且向上支持AuctionManager业务逻辑组件的实现。
图16.11显示了本系统中DAO组件和业务逻辑组件之间的依赖关系。
图16.11 DAO组件和业务逻辑组件的依赖关系图
前面已经介绍了每个DAO组件大致应该包含的方法,除此之外,每个DAO组件还应增加数量不等的查询方法,下面是系统中各DAO组件的具体实现。
AuctionUserDao接口除了包含前述DAO接口里通用的各方法外,还应该包含一个findUser ByNameAndPass方法,用于根据用户名和密码查找用户。
下面是该接口对应的代码:
程序清单:codes\16\auction\WEB-INF\src\org\crazyit\auction\dao\AuctionUserDao.java
上面定义了AuctionUserDao接口里应该包含的方法,这些仅仅是该组件所应该遵守的规范。定义接口的目的就是让规范和实现分离,接口只是定义一种规范,规定每个DAO组件必须实现哪些方法。随着系统采用不同持久化技术,DAO组件实现类可以完全不同,而DAO接口却是完全相同的。
对于应用的业务逻辑组件而言,它们仅仅依赖于系统的DAO接口,各组件面向接口编程,而不是面向具体实现类,从而可避免各组件以硬编码方式耦合在一起,因而可将业务逻辑组件从具体的持久化技术中分离出来。
每个DAO组件都至少提供了一个实现类,此处的DAO实现类基于Spring的HibernateDaoSupport实现。HibernateDaoSupport基类提供了如下两个方法:
setSessionFactory(SesionFactory sf):用于注入SessionFactory实例的setter方法。
getHibernateTemplate():返回持久化操作的HibernateTemplate实例的方法。
下面是AuctionUserDao组件的实现类代码:
程序清单:codes\16\auction\WEB-INF\src\org\crazyit\auction\dao\impl\AuctionUserDaoHibernate.java
通过上面的代码,可以发现这些DAO对象的实现简单得令人难以置信:大部分的数据库访问只需要一行或两行代码。这种简化得益于Spring提供的支持类——HibernateTemplate。HibernateTemplate是Spring 所提供的大量Template类之一,用于简化Hibernate的持久化操作。
提示
Template是Spring的一种设计哲学。Spring的作者认为,大部分Java EE项目的开发中需要经常重复相同的代码。在一些特定场景下,这些重复的代码可以被抽取成Template,程序开发者只需要传入用户需要定制的部分,而通用操作则由Template来完成。
与之类似的还有系统的ItemDAO组件,它也是由DAO接口和DAO实现类组成。ItemDao接口的代码如下:
程序清单:codes\16\auction\WEB-INF\src\org\crazyit\auction\dao\ItemDao.java
这个ItemDao接口的作用完全类似于前面的AuctionUserDao接口,是该DAO组件的一种规范,指定了该DAO组件应该包含哪些方法。下面是ItemDao接口实现类的代码:
程序清单:codes\16\auction\WEB-INF\src\org\crazyit\auction\dao\impl\ItemDaoHibernate.java
上面详细讲解了系统中包含的两个DAO组件,除此之外,系统中还包含另外3个DAO组件,这3个DAO组件与这里介绍的两个DAO组件大致相同,故此处不再赘述,读者可自行参考随书光盘中codes\16\auction\WEB-INF\src\org\crazyit\auction\dao下的代码。
16.3.3 配置系统DAO组件
本系统采用了Spring框架作为系统的IoC容器,故系统中的所有组件都处于Spring容器的管理下,包括DAO组件。使用Spring容器管理DAO组件有如下3个优势:
使用Spring容器作为DAO工厂,从而避免了自己实现DAO工厂,降低了编程难度。
DAO组件无须自己定位数据源,DAO组件的持久化访问所需的数据库连接可由Spring的IoC容器依赖注入。
DAO组件可以由Spring容器依赖注入给上层的业务逻辑组件。
配置DAO组件与配置Spring容器中的普通Bean没有太大的差别,而且因为系统中的3个DAO组件配置大致相同,都需要由容器来注入SessionFactory实例,故可以采用Bean继承类来简化DAO组件的配置。
使用Bean继承之前,应该先配置一个DAO模板,该DAO模板是所有DAO Bean的父Bean。下面是该DAO模板的配置代码:
配置了该DAO组件模板后,所有实际的DAO组件只需指定parent属性继承该DAO模板即可。下面是实际的DAO组件配置文件的配置代码:
程序清单:codes\16\auction\WEB-INF\daoContext.xml
注意
系统的DAO实现类中并未提供setSessionFactory方法,该方法由其父类HibernateDaoSupport提供,用于依赖注入SessionFactory引用。该配置文件中并未配置SessionFactory Bean,DataSource和SessionFactory的配置在另一个文件中。