BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Hades——JPA的开源实现

| 作者 Oliver Gierke 关注 2 他的粉丝 ,译者 池建强 关注 4 他的粉丝 发布于 2011年2月8日. 估计阅读时间: 16 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

简介

几乎每个应用系统都需要通过访问数据来完成工作。要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化。目前开发人员经常使用JPA来实现持久化库。JPA让持久化变得非常容易,但是仍然需要编写很多模板代码。Hades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现。本文是Hades的向导性教程,会带你走进Hades的世界,帮助你了解Hades在数据持久化方面能为你做些什么,并简要介绍了最新的2.0版本的新特性。

Hades的核心部分由通用的持久化库实现构成,不仅提供了基本的CRUD(增删改读)方法,而且增加了一些通用场景功能的实现,类似分页这样的功能你就不用自己实现了。还包括查询实体页、动态增加排序定义等能力。

查询

查询是使用最多的数据访问操作,如果你了解了Hades,就会意识到查询作为Hades的核心功能之一,定义和执行查询是多么容易,大大减少了工作量。一般完成一个查询操作包括以下三个步骤:

  1. 增加特定实体的库接口
  2. 增加查询方法
  3. 微调查询

首先你需要声明一个继承了GenericDao<Entity, Id>的接口,该类保证在Hades接口中定义的CRUD方法在你的接口中是有效的,如下:

public interface UserRepository extends GenericDao<User, Long> { … }

其次是根据业务需求为你的接口增加查询方法:

List findByUsername(String username);

这又会引出问题,那就是如何实现查询方法。如果你没有增加任何附加的元数据,Hades会尝试查找格式为{entity}. {method-name}的JPA查询方法,如果有效的话就使用该方法。如果没有找到任何可以解析的方法名,那就会创建一个查询方法。因此,之前的例子就会产生这样一样查询:select u from User u where u.username=?。查询解析支持更多的关键字,你可以随时在参考手册文档中找到它们。

如果想定义手工查询,你可以使用Hades的@Query注释功能,让该查询直接在方法中执行:

@Query("select from User u where u.lastname = ?");
List someReallyStrangeName(String lastname);

这样你可以自由的进行方法命名,既可以对查询定义实现完全控制,又不必担心那些查询模板代码。围绕着执行查询还有很多方式,例如使用分页查询、执行编辑查询等

引导Hades

到目前为止我们已经讨论了如何创建带有查询方法的库接口,接下来我们看一下如何使用这些接口。首先创建实体类的实例,然后根据该实例创建GenericDaoFactory的实例,通过工厂实例的getDao方法创建你需要的资源库,如下代码所示:

EntityManager em = … // Get access to EntityManager
GenericDaoFactory factory = GenericDaoFactory.create(em);
UserRepository userRepository = factory.getDao(UserRepository.class);

由于资源库经常通过依赖注入的方式被其客户端持有,所以Hades提供了优雅的方式与与Spring应用集成。在Spring的应用中引导Hades非常简单,只需使用Hades的命名空间,并声明可以被匹配到的基础包即可:

<hades:dao-config base-package="com.acme.*.repository" />

以上配置方式会选中所有继承了GenericDao的资源库接口,并为每个接口创建Spring的Bean。当然,命名空间支持更细粒度的配置,以实现精确控制。Hades的Eclipse插件实现了与Spring IDE和SpringSource工具套件的无缝集成,这样你就可以从其它Bean引用Hades的资源库,并在你的工作空间把它们标记为Spring的Bean。想了解详细信息请查看其参考手册。

审计

在系统中记录实体类的创建者、修改者和相关日期等信息是一个很常见的需求。Hades提供了监听器EntityListener,可以帮你透明的实现这些功能。要启用Hades的审计功能,只需要在orm.xml文件中定义AuditingEntityListener即可:

<persistence-unit-metadata>
    <persistence-unit-defaults>
        <entity-listeners>
            <entity-listener class="org.synyx.hades.domain.auditing.support.AuditingEntityListener" />
        </entity-listeners>
    </persistence-unit-defaults>
</persistence-unit-metadata>

并在Spring的配置中启动审计功能,如下:

<hades:auditing auditor-aware-ref="auditorAware" />

auditorAware是引用的Spring Bean,需要实现AuditorAware接口,通常是实现针对当前用户的安全查询功能。如果你只想跟踪创建和编辑日期,只需忽略该属性即可。想了解更多审计特性,请参考相关文档

JPA 2.0和事务性资源库

Hades2.0 是基于JPA2.0以及相关的Hibernate、EclipseLink和OpenJPA版本构建的。基于该版本的CRUD事务操作使用非常简单,开箱即用,对于相对简单的场景基本不需要再进行事务性的封装。未来结合资源库接口可以让事务管理变得更加简单。

public interface UserRepository extends GenericDao<User, Long> {
    @Transactional(readOnly = true);
    List<User> findByUsername();
    @Override
    @Transactional(readOnly = true, timeout = 60);
    List<User> readAll();
}

正如你看到的,你可以简单的通过为查询方法增加注释@Transactional的方式把它们加入事务。当然,也可以不用注释的方式,基于XML的事务配置也能运行的很好。在GenericDao中的CRUD操作具备默认的事务性(对只读操作来说就是把readOnly设置为true)。如果你想为这些方法重新配置事务,简单的为这些方法声明自定义的@Transactional即可实现。想了解更多详细信息,请参考事务相关的参考文档。

规范

Hades 最新版本的一个非常酷的特性是基于GenericDao的扩展即可符合规范。这里提到的规范指领域驱动设计的概念,DDD是由Eric Evans和Martin Fowler首次提出,从本质上捕捉实体的业务规则的一种开发方法。Hades提供的抽象方式可以很容易的基于JPA2.0的标准API实现领域驱动设计。在这里我们假设你已经读过上面提到的两位作者写的DDD相关的书籍。Hades提供了如下方式定义规范:

class BookSpecifications {
    public Specification<Book> hasAuthorWithFirstnameLike(final String firstname) {
        return new Specification<Book>() {
            public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                return cb.like(root.join("author").get("firstname"), firstname);
            }
        }
    }
    public Specification<Book> hasGenre(final Genre genre) {    
        return new Specification<Book>() {      
            public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {        
                return cb.equal(root.get( "genre"), genre);      
            }    
        }  
    }
}

当然,这并不是最优雅的代码片段(如果未来与Java 8里的单抽象方法(SAM)特性结果结合的话,效果会更好)。从积极的方面考虑,我们在资源库层面获得了执行规范的可能性:

bookRepository.readAll(hasAuthorWithFirstnameLike("Oliv*"));

好了,我们在声明式查询方面已经做了很多,不是吗?规范的能力真正闪光的时候是把它们整合为新的规范的时候。Hades提供了规范助手类,可以进行任意的合并:

bookRepository.readAll(where(hasAuthorWithFirstnameLike( "Oliv*").or(hasGenre(Genres.IT)));

通过这种方式,扩展资源库就变成了只是增加新的规范。少量的规范就可以帮助你使用类似DSL的柔性API查询资源库,而不是针对每次外部查询请求都使用查询方法访问资源库。想了解更多详细信息,请参考相关文档

扩展

2.0 版本的另一部分内容是扩展模块,可以实现Hades与展现层技术框架(例如Spring的MVC)的无缝集成。它提供了属性编辑器和Spring 3.0转换器,可以透明的把实体类与MVC控制器方法的绑定在一起,同时MVC扩展还可以动态的从HTTP请求中提取分页信息。一个展示用户列表的页面,在控制层的写法就是这样:

@Controllerclass UserController {  
    @Autowired  
    UserRepository userRepository;  
    @RequestMapping("/users")  
    public void showUsers(Pageable pageable, Model model) {    
        model.addAttribute("users", userRepository.readAll(pageable)); 
    }  
    @RequestMapping("/users/{id}")  
    public String showUser(@PathVariable("id") User user, Model model) {    
        model.addAttribute("user", user);    
        return"user"; 
    }
}

就像你看到的,showUsers方法不需要解析HttpServletRequest获取分页信息。另外请注意,在showUser(...)方法中绑定的id路径变量的参数已经是实体类了。由于Spring MVC基础框架的配置内容已经超出了本文要讨论的范围,如果想了解更多信息,请参考扩展模块配置信息的相关章节,其中提供了非常容易的设置样例

下一步?

展望未来,2.1.x版本之后,Hades可能会成为Spring Data项目的一部分,其核心将作为实现其它数据存储资源库的实现基础。Spring Data是SpringSource的项目,其目标是为新兴的数据库、特定的数据存储提供Spring的方言支持,包括NoSQL数据库。

总结

Hades 大大简化了使用JPA执行数据层的访问过程。你可以自由的进行精确的CRUD操作、执行查询和规范等。Hades既可以独立使用,可以方便的集成到 Spring中。除此之外,Eclipse的插件Spring IDE/STS和附加的Spring Roo 都可以非常容易的创建资源库。想了解更多信息,请参考项目网站

关于作者

Oliver Gierke是VMware公司的SpringSource部门的高级顾问,是Hades开源项目的项目主管。大约在两年前他在原公司Synyx启动了该项目。

查看英文原文: Hades - JPA Repositories Done Right


给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中 与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

Hibernate呢? by 熊 节

“又一个”开源实现?

标题有误 by Qiu Chris

Hades不能算JPA的实现,只能说是用来简化DAO开发的第三方框架。

id为什么一定要是 Long 类型呢? by x w

GenericDao<Entity, Id> 后面那个id为什么一定要是 Long 类型呢?</entity,>

标题翻译得太离谱 by Bai Hantsy

标题翻译得太离谱了,

草包无处不在啊 by Zeng Abrams

草包无处不在啊

SpringSource的项目 by Han Meng

与hibernate比,更好的能与spring 3.1 集成吧。

下载地址... by 郭 峰

竟然没有找到下载地址,真是晕死...

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

7 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT