`
longgangbai
  • 浏览: 7326312 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

使用Hibernate和Spring AOP购建一个范型类型安全的DAO

阅读更多

在采用了Java 5的范型之后,要实现一个基于范型类型安全的数据访问对象(DAO)就变得切实可行了。在这篇文章里,系统架构师Per Mellqvist展示了一个基于Hibernate的范型DAO实现。然后将介绍如何使用Spring AOP的introduction为一个类增加一个类型安全的接口以便于执行查询。

对于大多数开发者来说,在系统中为每一个DAO编写几乎一样的代码已经成为了一种习惯。同时大家也都认可这种重复就是“代码的味道”,我们中的大多数已经习惯如此。当然也有另外的办法。你可以使用很多ORM工具来避免代码的重复编写。举个例子,用Hibernate,你可以简单的使用session 操作直接控制你的持久化领域对象。这种方式的负面影响就是丢失了类型安全。

为什么你的数据访问代码需要一个类型安全的接口?我认为它减少了编程错误,提高了生产率,尤其是在使用现代高级IDE的时候。首先,一个类型安全的接口清晰的制定了哪些领域对象具有持久化功能。其次,它消除了类型转换带来的潜在问题。最后,它平衡了IDE的自动完成功能。使用自动完成功能是最快的方式来记住对于适当的领域类哪些查询是可用的。

在这篇文章里,我将展示给大家如何避免一次次地重复编写DAO代码,但同时还收益于类型安全的接口。事实上,所有内需要编写的是为新的DAO编写一个Hibernate映射文件,一个POJO的Java接口,并且10行Spring配置文件。
DAO实现

DAO模式对于任何Java开发人员来说都是耳熟能详的。这个模式的实现相当多,所以让我们仔细推敲一下我这篇文章里面对于DAO实现的一些假设:

    * 所有系统中的数据库访问都是通过DAO来完成封装
    * 每一个DAO实例对一个主要的领域对象或者实体负责。如果一个领域对象具有独立的生命周期,那么它需要具有自己的DAO。
    * DAO具有CRUD操作
    * DAO可以允许基于criteria方式的查询而不仅仅是通过主键查询。我将这些成为finder方法或者finders。这个finder的返回值通常是DAO所负责的领域对象的集合。

范型DAO接口

范型DAO的基础就是CRUD操作。下面的接口定义了范型DAO的方法:
public interface GenericDao <T, PK extends Serializable> {
 
    /** Persist the newInstance object into database */
    PK create(T newInstance);
 
    /** Retrieve an object that was previously persisted to the database using
     *   the indicated id as primary key
     */
    T read(PK id);
 
    /** Save changes made to a persistent object.  */
    void update(T transientObject);
 
    /** Remove an object from persistent storage in the database */
    void delete(T persistentObject);
}

 

实现这个接口

使用Hibernate实现上面的接口是非常简单的。也就是调用一下Hibernate的方法和增加一些类型转换。Spring负责session和transaction管理。

public class GenericDaoHibernateImpl <T, PK extends Serializable>
    implements GenericDao<T, PK>, FinderExecutor {
    private Class<T> type;
 
    public GenericDaoHibernateImpl(Class<T> type) {
        this.type = type;
    }
 
    public PK create(T o) {
        return (PK) getSession().save(o);
    }
 
    public T read(PK id) {
        return (T) getSession().get(type, id);
    }
 
    public void update(T o) {
        getSession().update(o);
    }
 
    public void delete(T o) {
        getSession().delete(o);
    }
 
    // Not showing implementations of getSession() and setSessionFactory()
}

 

Spring 配置

最后,Spring配置,我创建了一个GenericDaoHibernateImpl的实例。GenericDaoHibernateImpl的构造器必须被告知领域对象的类型,这样DAO实例才能为之负责。这个同样需要Hibernate运行时知道这个对象的类型。下面的代码中,我将领域类 Person传递给构造器并且将Hibernate的session工厂作为一个参数用来实例化DAO:

 

<bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl">
        <constructor-arg>
            <value>genericdaotest.domain.Person</value>
        </constructor-arg>
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
</bean>

可用的范型DAO

我还没有全部完成,但我现在已经有了一个可供作的代码。下面的代码展示了范型DAO如何使用:

public void someMethodCreatingAPerson() {
    ...
    GenericDao dao = (GenericDao)
     beanFactory.getBean("personDao"); // This should normally be injected
 
    Person p = new Person("Per", 90);
    dao.create(p);
}

 

这时候,我有一个范型DAO有能力进行类型安全的CRUD操作。同时也有理由编写GenericDaoHibernateImpl的子类来为每个领域对象增加查询功能。但是这篇文章的主旨在于展示如何完成这项功能而不是为每个查询编写明确的代码,然而,我将会使用多个工具来介绍DAO的查询,这就是 Spring AOP和Hibernate命名查询。

Spring AOP介绍

你可以使用Spring AOP提供的introduction功能将一个现存的对象包装到一个代理里面来增加新的功能,定义它需要实现的新接口,并且将之前所有不支持的方法委派到一个处理机。在我的DAO实现里面,我用introduction将一定数量的finder方法增加到现存的范型DAO类里面。因为finder方法针对特定的领域对象,所以它们被应用到表明接口的范型DAO中。

 

<bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/>
 
<bean id="abstractDaoTarget"
        class="genericdao.impl.GenericDaoHibernateImpl" abstract="true">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
</bean>
 
<bean id="abstractDao"
        class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
        <property name="interceptorNames">
            <list>
                <value>finderIntroductionAdvisor</value>
            </list>
        </property>
</bean>

在上面的配置中,我定义了三个Spring bean,第一个bean,FinderIntroductionAdvisor,处理那些introduce到DAO中但是不属于 GenericDaoHibernateImpl类的方法。一会我再介绍Advisor bean的详细情况。

第二个bean定义为“abstract”。在Spring中,这个bean可以被其他bean重用但是它自己不会被实例化。不同于抽象属性,bean的定义简单的指出了我需要一个GenericDaoHibernateImpl的实例同时需要一个SessionFactory的引用。注意 GenericDaoHibernateImpl类只定义了一个构造器接受领域类作为参数。因为这个bean是抽象的,我可以无限次的重用并且设定合适的领域类。

最后,第三个,也是最有意思的是bean将GenericDaoHibernateImpl的实例包装进了一个代理,给予了它执行finder方法的能力。这个bean定义同样是抽象的并且没有指定任何接口。这个接口不同于任何具体的实例。
扩展通用DAO

每个DAO的接口,都是基于GenericDAO接口的。我需要将为特定的领域类适配接口并且将其扩展包含我的finder方法。

 

 

 

public interface PersonDao extends GenericDao<Person, Long> {
    List<Person> findByName(String name);
}

 

上面的代码清晰的展示了通过用户名查找Person对象列表。所需的Java实现类不需要包含任何的更新操作,因为这些已经包含在了通用DAO里。
配置PersonDao

因为Spring配置依赖之前的那些抽象bean,所以它变得很紧凑。我需要指定DAO负责的领域类,并且我需要告诉Spring我这个DAO需要实现的接口。 

<bean id="personDao" parent="abstractDao">
    <property name="proxyInterfaces">
        <value>genericdaotest.dao.PersonDao</value>
    </property>
    <property name="target">
        <bean parent="abstractDaoTarget">
            <constructor-arg>
                <value>genericdaotest.domain.Person</value>
            </constructor-arg>
        </bean>
    </property>
</bean>

public void someMethodCreatingAPerson() {
    ...
    PersonDao dao = (PersonDao)
     beanFactory.getBean("personDao"); // This should normally be injected
 
    Person p = new Person("Per", 90);
    dao.create(p);
 
    List<Person> result = dao.findByName("Per"); // Runtime exception
}

上面的代码是使用类型安全接口PersonDao的一种正确途径,但是DAO的实现并没有完成。当调用findByName()的时候导致了一个运行时异常。这个问题是我还没有findByName()。剩下的工作就是指定查询语句。要完成这个,我使用Hibernate命名查询。
Hibernate命名查询

使用Hibernate,你可以定义任何HQL查询在映射文件里,并且给它一个名字。你可以在之后的代码里面方便的通过名字引用这个查询。这么做的一个优点就是能够在部署的时候调节查询而不需要改变代码。正如你一会将看到的,另一个好处就是实现一个“完整”的DAO而不需要编写任何Java实现代码。 

 

分享到:
评论

相关推荐

    SpringAOP整合Hibernate并使用事务(模拟买书的过程)

    通过以上步骤,我们可以成功地整合Spring AOP和Hibernate,利用事务管理实现一个安全、可靠的数据操作流程。这个示例展示了AOP和ORM结合在实际项目中的强大功能,以及它们如何简化和优化企业级应用的开发。

    Hibernate编程式事务与Spring Aop的声明式事务(spring与hibernate集成)

    当一个方法被标记为@Transactional,Spring会在方法执行前后自动处理事务的开始和结束,如果出现异常,Spring会自动回滚事务,否则在方法正常结束时提交事务。 例如,你可以在一个Service类的配置中写入如下代码: ...

    Spring+hibernate+junit+aop_ jar包

    标题中的"Spring+Hibernate+junit+aop"是一个经典的Java企业级开发组合,这些技术都是Java后端开发中的重要组成部分。让我们逐一深入理解这些知识点: 1. **Spring**:Spring 是一个开源的应用框架,核心功能包括...

    SpringMVC+springAOP+spring security+Hibernate整合实例代码

    Spring MVC、Spring AOP、Spring Security和Hibernate是Java开发中常用的四大框架,它们各自负责不同的领域,但在实际项目中往往需要进行整合以实现更高效、更安全的开发。本实例代码提供了一个完整的整合示例,涵盖...

    spring AOP依赖三个jar包

    1. aopalliance-1.0.jar:这是一个非常基础的AOP库,定义了AOP的核心接口,如`org.aopalliance.intercept.MethodInterceptor`和`org.aopalliance.aop.Advice`,这些接口为不同的AOP框架提供了统一的交互方式。Spring...

    hibernate和spring整合Java项目

    Spring是一个全面的企业级应用开发框架,核心特性包括依赖注入、面向切面编程(AOP)以及一系列的模块,如Spring MVC、Spring Data、Spring Security等。Spring的DI机制使得组件间的依赖关系得以解耦,提高了代码的...

    SpringAOP整合Hibernate并使用事务

    HibernateTemplate是Spring提供的一个便捷工具,它封装了SessionFactory的一些常用操作,如保存、更新、删除和查询等,可以减少手动处理Session的代码。 5. **事务配置** 在Spring配置文件中,使用`...

    springAOP所需jar包

    总的来说,Spring AOP提供了一个灵活且强大的平台,用于实现非侵入式的面向切面编程,简化了业务代码,提高了代码的模块化和可维护性。正确理解和使用这些jar包,将能更好地利用Spring AOP实现应用的解耦和扩展。

    spring AOP入门教程

    在编程领域,Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它为开发者提供了一种强大的方式来管理横切关注点,如日志、事务管理、安全性等。本教程将带你了解Spring ...

    Struts2+hibernate+spring整合泛型DAO

    Struts2、Hibernate和Spring是Java Web开发中的三大框架,它们各司其职,共同构建了一个强大的企业级应用体系。Struts2作为MVC(Model-View-Controller)框架,负责处理请求和展现视图;Hibernate是对象关系映射...

    hibernate与spring整合demo

    Hibernate是一个对象关系映射(ORM)工具,它简化了数据库操作,而Spring则是一个全面的企业级应用框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性。将Hibernate与Spring整合可以充分...

    hibernate3.0和spring结合(一看就懂)

    在【压缩包子文件的文件名称列表】中,只有一个文件名“hibernateSpring”。这可能是一个包含整个项目源代码和配置文件的文件夹,里面可能有以下几个关键部分: 1. **pom.xml**:Maven的项目对象模型文件,用于管理...

    Struts2+Hibernate+Spring整合开发深入剖析与范例应用03

    Spring还包含了数据访问抽象,如JDBC模板和DAO支持,以及对Hibernate的集成,方便在Spring环境中使用Hibernate。此外,Spring MVC是Spring提供的一个Web MVC框架,可以与Struts2协同工作,提供另一种实现MVC设计模式...

    使用Struts + Spring + Hibernate完成用户登陆笔记

    * 使用Spring框架来实现依赖注入和AOP,例如使用Spring的HibernateDaoSupport来实现DAO层的开发。 六、系统优点 * 使用Struts、Spring和Hibernate三种技术可以实现一个灵活、可维护和高效的用户登陆系统。 * 系统...

    hibernate-aop

    【hibernate-aop】是将面向切面编程(Aspect Oriented Programming,AOP)的概念应用于Hibernate框架的一个项目。在Java开发中,Hibernate是一个强大的对象关系映射(Object-Relational Mapping,ORM)工具,它使得...

    Spring AOP 日志管理 实例

    Spring AOP 日志管理 实例LoggingThrowsAdvice.java

    spring_aop.rar_spring-dao

    本资源“spring_aop.rar_spring-dao”是一个关于Spring AOP(面向切面编程)和Spring DAO(数据访问对象)的实例,旨在帮助开发者理解如何在Spring框架下实现AOP的控制反转,并有效地进行DAO层的操作。 首先,我们...

    使用Spring AOP对异常进行统一处理

    3.处理日志时,需要在每一个try-catch块包含一些处理代码,有时候异常处理的代码比正常执行代码还多,污染正常执行代码。 4.同样类型异常有不同的处理方式,使最终的处理变得复杂。 5.接口抛出异常,破坏封装,打破...

    使用myeclipse集成struts,hibernate,spring的一个示例程序

    【使用MyEclipse集成Struts、Hibernate、Spring的示例程序】 在Java企业级应用开发中,曾经EJB因其强大的功能和复杂的配置而备受关注。然而,随着Java开源项目的崛起,开发者有了更多轻量级的选择,例如Struts、...

Global site tag (gtag.js) - Google Analytics