`
mmdev
  • 浏览: 12844876 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

使用 EJB 3.0 Java Persistence API 设计企业应用程序

 
阅读更多
本文将介绍 Java™ Platform, Enterprise Edition (Java EE 5) 的一种设计方法,它利用了 Enterprise JavaBeans™ (EJB) 3.0 新的 Java Persistence API (JPA)。JPA 提供了一种标准的对象关系映射解决方案,该解决方案避免了依赖第三方框架(如 Hibernate)。您将看到示例应用程序的详细内容,其中验证了本方法并阐明关键设计决定。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

期待已久的下一版本 Java EE 5 即将发布(参见 参考资料 获得规范和预览版的链接)。Java EE 5 许多新功能都包含经过修补的 EJB 架构,其突出特性之一是 JPA。由于具有容器内和容器外持久性选项,JPA 为 J2EE 架构师带来一系列全新设计选择。本文将着重介绍容器内应用程序的设计,此类应用程序依赖 EJB 容器提供企业服务,如事务处理和安全性。

我将使用您熟悉的 PetStore 应用程序进行测试,以证明 JPA 的功能以及它如何向传统 J2EE 设计模式发起挑战。本应用程序比较琐碎,所以不提供详尽的实现细节。我将用代码摘录对设计注意事项进行说明(完整开放源码的连接请参见 下载 )。本文假设您熟悉 EJB 3.0 基本概念和对象关系(OR)映射基本概念。(若需了解这两个主题的更多信息,请参阅 参考资料 )。

设计概述

示例 PetStore 应用程序是基于 Web 的电子交易应用程序,它实现以下用例:

  • 浏览产品
  • 查找产品
  • 维护账户
  • 维护购物车
  • 创建订单

本应用程序被设计为具有三个主要逻辑层的多层 Java EE 应用程序:

  • 表示层(并非本文的重点)使用 Struts 框架。

  • 服务层是一种简单的服务 facade,将所有工作委托给其协作者。服务层的目的是分离服务供应与服务实现。

  • 数据访问层是一系列作为无状态会话 bean 实现的粗粒度 Data Access Objects (DAO)(参见 参考资料)。出于持久性的需要,它们都依赖 Java 持久性实体管理器。

应用程序域模型由 EJB 3.0 实体 bean 表示并用于层间的通信。当域对象离开数据访问层时,它与实体管理器脱离。当重新进入数据访问层时,它需要重新连接到实体管理器。

注释似乎是 Java 5 的一个广泛采用的特性,JPA 也不例外。注释可用于指定 OR 映射 —— 在 dW 文档和教程中您经常可以看到 —— 而 PetStore 应用程序出于相同目的使用它们。然而值得一提的是您还能通过映射文件的方式指定 OR 映射。本文稍后的 OR 映射 一节将探讨并比较这两种可选方式。

我在 Jboss 应用服务器中开发并部署 PetStore 应用程序(参见 参考资料)。我使用商用数据库完成大多数开发工作并将应用程序后端移植到 PostgreSQL 数据库(OR 映射 一节包含了关于使用 JPA 时您应该了解的数据库迁移的潜在影响的讨论)。

本案例分析的目的之一是符合设计标准,允许高度可测试的实现。如 测试 一节所见,您能够使用一系列测试技术来测试 PetStore 应用程序。

PetStore 应用程序充分利用了这一事实:它是规则的 Web 应用程序。主要优点是所有层能够运行在相同的 JVM 中,免除了组件分发的需要。本文的 远程处理 一节简要介绍了为应用程序添加远程处理功能的方法。




服务层

服务层被设计为服务 facade。它由 PetStoreService 这一无状态会话 bean 实现。Bean 要完全依靠其协作者来提供 Web 服务。

因为简化的 PetStore 要求被限定于从数据库检索数据并把数据存储于数据库,惟一的协作者就是 DAO。真正的应用程序能够调用 Web 服务,通过 RMI/IIOP 或资源适配器访问其他应用程序,并生成电子邮件消息等。所有此类型的功能都需要其他协作者支持。

可通过 @EJB@Resource 注释注入协作者(如清单 1 所示)或通过 @PostConstruct 方法注入协作者(如清单 2 所示):


清单 1. 使用 @EJB 注入协作者
@EJB(beanName = "AccountDao")
AccountDao accountDao;


清单 2. 使用 @PostConstruct 注入协作者
MessageSource messageSource;
@PostConstruct
public void init() {
messageSource = new MessageSourceImpl("exceptions");
}

选择 bean 实现类的测试策略的主要因素是类完全依赖协作者来提供服务。这意味着类和协作者的交互作用需要被验证。正如您在 测试 一节看到的,模仿对象方法完全满足该目标。


数据访问层

数据访问层被设计为一系列粗粒度的 DAO。DAO 被实现为无状态会话 bean,一个 bean 对应一个逻辑域:AccountDaoOrderDaoProductDao

每个 bean 都要把实体管理器注入到其中:

@PersistenceContext(unitName = "manager1")
protected EntityManager em;

这是应用程序中 持久性调用类(persistence-aware) 最多的层。它广泛使用全新的 Enterprise JavaBeans Query Language(EJB QL)(参见 参考资料)。所有持久性相关的行动都在该层发生,例如:

profile = (UserProfile) em.createQuery(
"from UserProfile up where up.login = :login").setParameter(
"login", login).getSingleResult();

下面是另一个例子:

em.persist(account);

事实上这些类是持久性调用类(persistence-aware),需要一种容器内测试策略,这将在 测试 一节进行描述。


域模型

您可以把 JPA 看作是众所周知的透明持久性技术(如 JDO 和 Hibernate)的继承者。尽管透明持久性可看作一个附加(add-on)服务,可被应用到忽略持久性的 Plain Old Java Objects (POJO)中,但 JPA 还是对域对象施加了少量限制。

首先,您通常要具有一个映射到对应数据库表主键的(代理)对象标识符:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AccountSeq")
@Column(name = "account_sysid")
public Integer getAccountId() {
return this.accountId;
}

其次,在联机事务过程(OLTP)环境中,需要一个 version 字段或 JavaBean 属性以进行乐观并发控制:

@Column(name = "row_version")
@Version
public int getVersion() {
return version;
}

最终,如果您选择使用注释方式的映射,映射注释将分布在代码周围。

另一种限制源自于这样一个事实:域对象可以通过由实体管理器所管理的域对象所在的层访问,也可以通过分离它的所有其他层访问。此外,对象可能是新的或已删除的。一般情况下,对象的行为取决于其持久性状态。例如,假设在实体管理器中执行以下这行代码:

int size = attachedProduct.getItems().size();

项集合使用给定产品的项填充,size 变量的值大于 0。如果使用默认懒加载(lazy)配置的一对多关联,并在表示层中执行同一行代码,size 变量的值为 0。 换句话说,在实体管理器之外(在实体管理器内也没关系)无法把 非活动(lazy) 对象与 活动(eager) 对象区分开。解决此问题的方法是强制执行项目规范和约定。

在域对象中,您可以把相同的推理应用到业务方法。无论是否在实体管理器中,它们都应该准备好在任何层中调用。这就是把域对象中的业务方法数量限制为必要的最少数量的理由。

虽然有上述各种情况,域对象依然保留许多 POJO 特性。这意味着您可以使用 plain old Java test (POJT) 对业务方法进行测试,POJT 这一术语引自 Expert One-on-One J2EE Development without EJB 一书(参见 参考资料。)



OR 映射

OR 映射是围绕 JPA 设计的应用程序的重要元素。它直接影响实体管理器填充域对象的方式。因此,变更映射能够在表示层觉察到。变更获取类型或级联类型可能将产生非常不利的影响。

正如前面所述,有两种定义映射的方法:元数据(注释)和映射文件。尽管我们高度提倡采用元数据的方法,但您应该也注意到了它所带来的不便。从本质上 讲,此方法牵涉应用程序的两个逻辑层:域模型和映射信息。因为这两个层是分散的,所以这两个层需要使用不同技术进行单独测试。元数据方法本身不会影响层的 可测试性。更确切的说,元数据方法使这两个层好像只是一个层,由于受一系列因素的影响,这可能会引起问题。

影响映射方法选择的一个因素是项目小组结构。在只有少数开发人员参与的小型项目中,表的数量很少(一般说来少于 100 个表)而且没有专职的映射人员,因为通常使用注释会更加快速,所以把注释方法看作定义映射也许是最佳选择。对于拥有专职映射人员或映射小组的中型和大型项 目来讲,使用映射文件的方法才是更好的选择。该方法可以降低资源争用并使开发过程具有另一种自由度。基于元数据的映射方法证实是 PetStore 应用程序更加节省时间的方法。

OR 映射层的目的是使其余应用程序免受底层数据库变更的影响。当把 PetStore 应用程序后端迁移到 PostgreSQL 时,无需对映射层作出任何变更。这可能要归结于这一事实:原始数据库和 PostgreSQL 这两者均支持序列,因此主键生成策略保持完好。一般情况下,您应该对与对象 ID 处理相关的映射区域进行重写。

对映射的全面测试覆盖极为重要。必须覆盖所有关系映射以确保对获取行为和过渡持久性进行测试。您能够利用容器外使用的 JPA 来执行该任务(将在下一节进行详细介绍)。



测试

服务层设计的关键要素是,关注与底层的协作以提供请求的服务。这需要考虑到使用动态模仿对象的可靠测试策略。我使用 EasyMock 框架(参见 参考资料)来实现测试方法。

DAO 层具有强大的数据库内聚力。这就是可靠测试需要某类容器内策略和数据库访问的原因。尽管这对于远程 EJB 很容易,还是需要考虑适合本地 bean 的有意义的方法。此处令人困扰的因素是:

  • 需要容器内测试 facade
  • 域对象是非连续的,所以全部验证需要发生在容器内。

JBoss Embeddable EJB3 容器(参见 参考资料) (撰写这篇文章时尚处于测试版阶段)被证实是更适当的选择。因为能够从单元测试启动 JBoss Embeddable EJB3 容器,这样所有代码都运行在同一 JVM 中。使用可嵌入容器的容器内测试可实现它的目标,但过程比较缓慢,因为容器启动时间就需要大概 30 秒。这种问题可能是由较早的产品状态造成的,可通过合理的配置改进。

我采用 POJT 对域模型类的业务方法进行测试。不需要其他测试技术,况且其他测试技术不适合这些类。

OR 映射是一个需要穷举测试覆盖的主要层。该层对数据库非常敏感,所以该层不能应用模仿对象或 POJT 技术。但是,您可以利用 JPA 的容器外功能。我就使用这种策略来测试 PetStore 或 OR 映射层。

您需要牢记测试中的测试关联和过渡持久性行为的重要性。这样您才能及早注意到获取类型的变更或级联类型值的变更,并采取适当的措施。


远程处理

PetStore 应用程序设计的关键特性是它的本地特性。使应用程序的所有逻辑层运行在同一 JVM 中,这种方法具有很多优点。有关该主题的详细讨论,请参阅 Expert One-on-One J2EE Development without EJB(参见 参考资料)。

不过,应当说明的是:通过远程处理 facade,您可以轻松向应用程序添加远程处理功能。远程处理 facade(而不是我在前面描述的服务 facade)公开了一个远程界面,它具有两个职责:进行域模型和顺序数据传输对象(DTO)(参见 参考资料)之间的相互转换和在服务 facade 上调用适当的方法。

使用远程无状态会话 bean 能够实现本应用程序。唯一障碍是创建其他 DTO 层和进行它们与域模型之间相互转换。然而您需要它来确保实现整洁的界面以及与远程客户机的松散耦合。


结束语

EJB 3.0 和 JPA 毫无疑问将是 Java EE 5 的主要卖点。在某些领域中,它们给正常的 Java 社区带来竞争优势,并使 Java 在其他领域与竞争对手不分伯仲。(不可否认的是,目前某些领域尚不存在基于标准的方法。)

过去数年来,Spring Framework(参见 参考资料)一直是 EJB 在企业领域的主要竞争对手。EJB 3.0 规范解决了很多促进 Spring 兴起的问题。随着它的出现,EJB 3.0 毫无疑问比 Spring 提供了更好的开发体验 -- 最引人注目的优势是它不需要配置文件。

JPA 提供一种标准的 OR 映射解决方案,该解决方案完全集成到 EJB 3.0 兼容的容器中。JPA 的前辈将会继续稳定发展,但是业务应用程序中的 raw 使用将可能会减少。实现 JPA 兼容的实体管理器似乎很可能是此类技术的发展方向。

在撰写本文时,EJB 3.0 规范还处在建议的最终草案(Proposed Final Draft)阶段(参见 参考资料)。以下是一些未解决的问题以及与 JPA 相关的预实现:

  • • 当前形式的 JPA 规范没有定义只读实体 bean。这让人困惑,因为兼容 EJB 2.1 规范的实体 bean 支持这种特性。Spring 框架也支持只读事务。

  • • 可插入的持久性提供者概念仍处于未交付的阶段。

  • • 标准乐观并发异常 -- OptimisticLockException -- 首次出现在 EJB 3.0 Proposed Final Draft 中。在持久性提供者执行它以前 ,您还需要使用特定于提供者的异常,如 Hibernate 的 StaleObjectStateException,来检测乐观并发问题。暂时,这种情况限制您的实现只能采用特定的持久性提供者。

Java EE 系列规范的较大问题与 JPA 没有任何关系。Java EE 系列规范的问题涉及到 Web 和 EJB 容器之间的集成。Spring 在此领域仍然具有主要竞争优势。JBoss 的 Seam 项目(参见 参考资料)尝试使用自定义的方法来解决这一问题。Caucho Resin 应用服务器(参见 参考资料)试图扩展容器边界并支持在 Web 容器中使用 @EJB 注释。我们希望 Java EE 5.1 将解决层集成的问题,为我们提供一个全面而标准的依赖性注入方法。



下载

描述 名字 大小 下载方法 PetStore
j-ejb3jpapetstore.zip 149KB HTTP
关于下载方法的信息


参考资料

学习

获得产品和技术


关于作者

Borys Burnayev 是一名具有超过 12 年从业经验的软件开发人员,过去 5 年中,他从事 Java 及相关技术的工作,最近开始专注于 J2EE 设计问题与对象关系技术。Borys 拥有应用数学的硕士学位。他还拥有 Sun Certified Architect 技术认证和 Sun、Oracle 、IBM 多家公司的其他技术认证。

分享到:
评论

相关推荐

    Pro EJB 3 Java Persistence API

    Apress-Pro EJB 3 Java Persistence API.pdf

    Java Persistence API(EJB3.0中的 JPA 规范说明)

    Java Persistence API(EJB3.0中的 JPA 规范说明) 。

    EJB3.0规范和API文档

    ejb-3_0-pfd-spec-persistence ejb-3_0-pfd-spec-simplified ejb-3_0-fr-spec-ejbcore

    Mastering EJB 3.0 4th(E)

    In-depth coverage of the Java Persistence API and using POJO entities with EJB is also included. By reading this book, you will acquire a deep understanding of EJB 3.0. What you will find here This...

    Java标准版的EJB Persistence(一)

    自从起草EJB 3.0的规范开始,无论是在客户端还是在服务器端的应用程序里,Java的类就一直有一种单一的、标准的persistence机制。Java 5的Annotations(批注)功能很容易使用。本文将介绍如何使用它。在本教程里,...

    EJB3.0+JPA+javaSe环境

    Ejb3.0的规范是使用Java Persistence API.

    Mastering EJB 3.0

    - Basic and advanced concepts (such as inheritance, relationships, and so on) of Java Persistence API defined entities - Information on integrating EJB applications with the outside world via the Java...

    ejb3.0 jpa

    JPA(Java Persistence API)作为Java EE 5.0平台标准的ORM规范,将得到所有Java EE服务器的支持。Sun这次吸取了之前EJB规范惨痛失败的经历,在充分吸收现有ORM框架的基础上,得到了一个易于使用、伸缩性强的ORM规范。...

    Java Persistence API 2.0 FINAL 官方文档.pdf

    This document is the specification of the Java API for the management of persistence and object/relational mapping with Java EE and Java SE. The technical objective of this work is to provide an ...

    Java Persistence API 2.0 FINAL文档

    This document is the specification of the Java API for the management of persistence and object/relational mapping with Java EE and Java SE. The technical objective of this work is to provide an ...

    Apress.Pro.EJB.3.Java.Persistence.API.May.2006.zip

    ejb3.0 API

    EJB3.0_JPA_教程

    JPA(Java Persistence API)作为 Java EE 5.0 平台标准的 ORM 规范,将得到所有 JavaEE 服务器的支持。

    openjpa实体标识的生成策略

    JPA(Java Persistence API)是 EJB 3.0 新引入的数据持久化编程模型。JPA 充分利用了注释(Annotation)和对象/关系映射,为数据持久化提供了更简单、易用的编程方式。OpenJPA 是 Apache 组织提供的 JPA 标准实现。...

    JPA从入门到精通

    J2EE 4规范中最为人所熟悉的用来处理数据持久的Entity Bean,在Java EE5中被推到重来,取而代之的是java开发的通用持久化规范Java Persistence API 1.0, 其实就是完全重新定义了的Entity Bean规范; ………………...

    hibernate3所需完整jar包

    压缩包内包含antlr-2.7.6.jar、commons-collections-3.1.jar、commons-logging-1.1.3.jar、dom4j-1.6.1.jar、ejb3-persistence.jar、hibernate3.jar、hibernate-jpa-2.0-api-1.0.1.Final.jar、javassist-3.12.0.GA....

    JPA 注解参考文档

    JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 JPA支持XML和JDK5.0注解两种元数据的形式。 JPA的总体思想和现有Hibernate、TopLink、...

    Java/JavaEE 学习笔记

    第四章 JPA(Java Persistence API)...332 第五章 Advanced Persistence Concepts(JPA-高级持久化)..336 第六章 事务...........341 Spring学习笔记...............345 第一章 Spring概述.............................

    JPA注解参考文档

    JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 JPA支持XML和JDK5.0注解两种元数据的形式。 JPA的总体思想和现有Hibernate、TopLink、...

    整理后java开发全套达内学习笔记(含练习)

    应用,应用程序 [,æpli'keiʃәn]' (application crash 程序崩溃) arbitrary a.任意的 ['ɑ:bitrәri] argument n.参数;争论,论据 ['ɑ:gjumәnt]'(缩写 args) assert (关键字) 断言 [ә'sә:t] ' (java 1.4 之后...

    Java™ Servlet 规范.

    1.5 与 Java 平台企业版的关系 ......................................................................................................................14 1.6 与 Java Servlet 规范 2.5 版本间的兼容性 .........

Global site tag (gtag.js) - Google Analytics