用EJB3.0 简化EJB开发

简介:         引入 Enterprise JavaBeans ( EJB ) 是为了构建分布式组件。
        引入 Enterprise JavaBeans ( EJB ) 是为了构建分布式组件。最初 , 该技术承诺可以解决 CORBA 的所有问题并降低其复杂性。作为J2EE的核心,EJB经历了几次较大的修订,并加入了许多特性,因而变得臃肿起来。从一开始,大部分开发人员就非常钟爱EJB,甚至在没有任何意义的情况下也在其应用程序中使用EJB。当项目不能正常扩展,又在使用EJB时,很多开发人员都会责怪EJB。

  EJB 开发从来就没有变得更为容易 , 相反 , 随着 EJB 规范的相继发布, 它还变得越来越复杂了。由于其复杂性和本身庞大的体系,EJB被喻为一头大象。许多开发人员认为EJB就像油炸圈饼外边多的一层糖。在狂热奉行低糖饮食和低碳水化合物的年代,EJB专家委员会别无选择,只能努力提供“低糖”的EJB,以简化EJB的开发。EJB 3.0专家委员会在JavaOne 2004会议期间发布了 EJB 3.0规范 的第一个公开草案,并给出了一个轻量级模型的示例图片。

  新的 EJB 模块 给人的第一感觉是看上去很漂亮 , 在本文中 , 我们将讨论 EJB 3.0 如何把自己包装得更为小巧玲珑 , 从而吸引开发人员的眼球。在接下来的另一篇文章里,我们将讨论EJB3.0如何简化持久性模型。

EJB 模型的复杂性

  在开始讨论EJB 3.0带来的新特性之前,让我们了解一下当前 EJB 模型的复杂性。

  • 当前的 EJB 模型 需要创建若干个组件接口并实现若干个不必要的回调方法。
  • 这些组件接口需要实现 EJB Object 或 EJB LocalObject , 且需要处理许多不必要的异常情况。
  • EJB 部署描述符复杂 , 且易出错。
  • 容器管理的持久性基于 EJB 模型 , 也十分复杂 , 不利于开发和管理。缺乏一些基本功能(如按标准方法使用数据库序列定义主键等),且 EJBQL 十分受限。
  • 由于有继承性和多态性方面的约束 , EJB 组件与其源对象并不相同。
  • EJB 的主要缺点之一就是不能在 EJB 容器外测试 EJB 模块 ,而且 对开发人员而言 , 要在容器内调试 EJB 是件可怕的事。
  • 如果用过 EJB , 您就会知道查找和调用 EJB 的有多复杂了。为了在应用程序中使用 EJB ,您必须了解 JNDI 的每个细节。

简化开发人员视图

  如果用过最新的规范开发 EJB , 就会发现开发一个类似于 HelloWorldEJB 这样简单的 EJB 有多困难。您至少需要两个接口、一个bean类和一个部署描述符。大多数开发人员都在想:我要这些干什么?在 Oracle JDeveloper 、 Eclipse 和 XDoclet 等IDE中,开发人员可以轻松地完成这些琐事,不过,在将EJB部署到所选的容器之前,开发人员仍需负责编译这些类并包装部署描述符。

  EJB 3.0希望使用以下方法来克服这种复杂性:

  • 无需使用接口和部署描述符 , 而是由容器使用元数据标注生成。
  • 将 普通 Java 类用作 EJB ,将 普通业务接口用于EJB。

元数据标注

  EJB 3.0 对元数据标记的依赖性很强。在 JSR 175 下元数据标记得以标准化 , 且将包含在 J2SE 5.0 中。标注是一种面向属性的编程,与Xdoclet类似。不过 , 与需要预编译的 XDoclet 不同 ,标注是在 编译时由 Java 编译器编译到类中的 ( 取决于如何设置 @Retention ) 。对开发人员而言,标注是类似于public一样的修饰符,可以在类、字段、方法、参数、本地变量、构造函数、枚举及包中使用。可以指定可用于生成代码、归档代码或在运行时提供特殊服务(增强的业务级安全或特定业务逻辑)的属性,从而在Java代码中使用标注。J2EE 1.5(5.0)的目标是用标注来简化开发,因而它会提供自己的一组标注。标注使用@来进行标记,如下所示:

  @Author("Debu Panda")
  @Bean
  public class MySessionBean 

  EJB 3.0 的目标是为了简化开发 , 因而要使用元数据标注来生成若干类似接口一样的工件 ,要 使用标注而不使用部署描述符。

使用 POJO 和 POJI

  按照规范化的术语 , JavaBeans 和接口经常分别被称为 Plain Old Java Objects ( POJO ) 和 Plain Old Java Interfaces ( POJI) 。现在的EJB类和接口将分别类似于POJO和POJI。像home接口之类的不必要工件将不再需要。

  开发人员要么必须在 javax.EJBpackage 中实现一个 EJB 接口 ( SessionBean 、 EntityBean 或 MessageDrivenBean ),要么就是 在 bean 实现类中使用标注。可以使用 Stateless 、 Stateful 、 MessageDriven 或 Entity 标注 bean 类。例如 , 若将一个Stateless EJB 定义为 HelloWorld ,可以这样 定义该 EJB :

@Remote
  @Stateless public class HelloWorldBean {
 public String sayHello(String s)
  { System.out.println("Hello: "+s; }
  } 

  EJB 的接口可以是远程的 , 也可以本地接口 ,都 不必实现 EJBObject 或 EJBLocalObject 。必须为 EJB 提供业务接口 , 并在 bean 类中实现该接口 ; 或者在部署期间生成该接口。对于Entity bean,接口是可选的;不过对于 SessionBean 和 MessageDrivenDriven ,接口则是必需的。如果没有为session bean实现接口,将会生成一个bean接口。生成的接口类型可以是本地的或远程的,取决于在bean类中使用的标注。从上面的代码示例可以很清楚地看出, @Remote 是用于为 HelloWorld bean生成远程接口的。如果需要,可以为EJB同时提供远程接口和本地接口。

  上面的例子清楚地表明 , 开发人员没有必要进行大量的寻常任务 , 如定义接口和实现回调方法。

  生成的接口的名称源自 bean 实现类的名称。生成的接口对开发人员来说的确不错。不过,我认为生成接口并没有多大优势,因为大多数IDE(如Oracle Jdeveloper)都可动态生成这些接口。

  草案中并没有清楚地说明什么是 EJB 查找的客户端要求 ,以及 如何得到调用该 EJB 所需的这些接口。我建议不要使用生成的接口,原因如下:

  • 生成的接口的名称将从 bean 名称派生
  • 您可能不愿意在生成的接口中公布 EJB 中 的某些方法 , 而默认情况下 , 生成的接口将公开所有的方法。
  • 您需要客户端接口来调用 EJB 。

  不再需要回调方法

  EJB2.1 及以前的版本要求为每个 EJB 实现若干个生命周期方法 , 如 ejbPassivate 、 ejbActivate 、 ejbLoad 、 ejbStore 等 , 即使不需要这些方法 , 也要这样做。例如 , Stateless 会话 bean 不需要 ejbPassivate , 但仍需要在 bean 类 中实现该方法。由于现在的EJB3.0与普通Java类类似,因此实现这些生命周期方法已经不是必需的了。若在EJB中实现回调方法,容器就会调用该方法。

  惟一的例外是 Stateful 会话 bean 中的 ejb Remove 方法 , 在 Stateful 会话 bean 中可以使用 Remove 标注来标注 Stateful 会话 bean 业务方法。如果使用此标注 , 它将会在被标注的方法完成 ( 正常或异常完成 ) 后提示容器删除 Stateful 会话 bean 实例。例如 , 可以指定以下代码在执行完 checkOut 方法后删除 Stateful 会话 bean 实例。

@Stateful public class Cart {
...
...
@Remove public void checkOut() {
...
}
}

  标注与部署描述符对比

  如前所述 , EJB 将不再需要部署描述符 , 而将使用标注。部署描述符中的每个属性的默认值都将被选定,开发人员无需指定这些属性,除非要使用默认值以外的值。可以在bean类本身中使用标注来指定这些值。 EJB 3.0 规范为开发人员定义了一组元数据标注 , 如 bean 类型、接口类型、资源引用、事务属性、安全性等。举例来说,假设我们希望对某一特定的EJB进行资源引用,则进行如下定义:

@Resource(name="jdbc/OracleDS", resourceType="javax.sql.DataSource")

  J2EE 供应商 ( 如 Oracle 、 BEA 、IBM ) 将在其特定于供应商的部署描述符中添加属性标注 , 开发人员将使用这些标注来避免使用部署描述符。对于开发人员而言,这相当有吸引力,因为没有了他们最讨厌的XML描述符。不过,这也带来一些问题,在使用标记的之前,我们需要多几分谨慎。

  • 这妨碍了应用程序可移植性目标的实现 , 因为如果 EJB 使用特定于供应商的部署描述符 , 并且不重新编译 / 重新包装 EJB ,变化 就不会如愿以偿。
  • 无需逐个查看 ejb ,部署描述符就为汇编器 / 部署器 ( ejb-jar ) 提供了 EJB 模块的完整视图,它们还按照每一部署的要求调整这些视图。如果描述符不可用或直到部署结束时才生成,那么后果可能会不堪设想。
  • 各种工具使用部署描述符在 EJB 模块 中识别 ejb , 当在容器间进行迁移时这会非常有用。
    EJB 3.0 规范还提出了一种重写部署描述符中标注的方法。不过,规范中并没有给出重写标记的具体细节。

  毫无疑问 , 不再使用部署描述符将使新的开发人员能够更轻松地开展工作 , 但如果使用不当 , 可能会引发管理问题。

简化容器管理的持久性

  EJB 3.0 对 CMP 实体 bean 进行了全面的革新 ,以吸引 开发人员的注意力。持久性框架 ( 如 OracleAS TopLink ) 、开放源码的 Hibernate ) 已成为开发 J2EE 应用程序持久性框架的宠儿,而 实体 bean 由于既 复杂又沉重,已不再受欢迎。 EJB 3.0 采用了一个类似 TopLink 和 Hibernate 的轻量级持久性模型 , 以简化容器管理的持久性 , 而这对开发人员而言无疑很有诱惑力。我们来简单了解一下该实体bean计划,关于持久性改进方面的详细内容,我们将在另一篇文章中讨论。

  实体 bean 正在 作为 POJO 而重获新生,实体 bean 也 将不再需要组件接口。现在实体bean将被视为纯粹的对象,因为它也将支持继承性和多态性。

  以下是 实体 bean 的源代码 :

@Entity public class Employee{
  private Long empNo;
  private String empName;
  private Address address;
  private Hashmap projects = new Hashmap();
  private Double salary;
  @Id(generate=SEQUENCE) public Long getEmpNo() {
  return empNo;
  }
  protected void setEmpNo(Long empNo) {
  this.empNo = empNo;
  }
  public String getEmpName() {
  return EmpName;
  }
  public void setEmpName(String EmpName){
  this.EmpName = EmpName;
  }
  @Dependent public Address getAddress() {
  return address;
  }
  public void setAddress(Address address) {
  this.address = address;
  }
  public Set getProjects() {
  return projects;
  }
  public void setProjects(Set projects) {
  this.projects = projects;
  }
  public Double getSalary() {
  return salary;
  }
  public void setSalary(Double salary) {
  this.salary = salary;
  }
  ....
  }

  观察以上代码 , 可以发现此 bean 类是当前 实体 bean 的实体类 , 而不是抽象类。

  EJB QL 中对查询功能进行了若干改进 ,并 在 实体 bean 中支持 SQL 查询。提出类似于 Hibernate 的新 EntityManager API ( TopLink ' Session API 的一个简化版本)用于对实体 bean 进行操作 , 即创建、删除和查找 实体 bean 。。

  我们将在下一篇文章中仔细探讨提出的 CMP 实体 bean 的细节。

简化 EJB 的客户端视图

  使用 EJB ( 即查找和调用)非常复杂 , 即使在应用程序中已经配置了 EJB 。J2EE 1.4和EJB 3.0规范正是要简化EJB的客户端视图。

  若现在就想使用 EJB , 则必须在部署描述符中定义 ejb-ref 或 ejb-local-ref , 查找 EJB 然后再调用。若想调用HelloWorld EJB,以下是在当前实现中调用EJB的最简单方法。

  首先在部署描述符中定义 EJB 引用 , 如下所示 :

<ejb-ref>
  <ejb-ref-name>HelloWorldEJB</ejb-ref-name>
  <ejb-ref-type>Session</ejb-ref-type>
  <home>hello.HelloWorldHome</home>
  <remote> hello.HelloWorld</remote>
  </ejb-ref>
  然后 , 利用以下代码查找 EJB 。必须显式处理 bean 实例的 EJB 查找和创建异常情况。
try
  {
    Context context = new InitialContext();
	HelloWorldHome helloHome =
	  (HelloWorld)PortableRemoteObject.narrow(context.lookup
     ("java:comp/env/ejb/HelloWorldEJB"), HelloWorldHome.class);
	HelloWorld hello = helloHome.create();
	  ....
   }
    catch(RemoteException e)
	{
	  System.err.println("System/communication error: " + e.getMessage());
	}
	catch(NamingException e)
	{
	  System.err.println("Communication error: " + e.getMessage());
	}
	catch(CreateException e)
	{
	  System.err.println("Error creating EJB instance: " + e.getMessage());
	}

  对于 环境变量 , EJB 3.0 建议使用另一种方法,即使用 setter 注入来查找和调用 EJB 。

  以下代码是使用 setter 注入在另一个 EJB 中查找 HelloWorldEJB 的方法。

@Inject private void setSessionContext(SessionContext ctx)
  {
  this.ctx = ctx
  }
  ...
  myHello = (HelloWorld)ctx.lookup("java:comp/env/ejb/HelloWorldEJB"); 

  仔细研究上面的代码 , 可以发现 setSessionContext 方法用 @Inject 进行了 标注 , 目的是将依赖注入用于该方法。注入的方法将由容器调用,以在该EJB上调用任一业务方法前设置EJBContext。

  另一个注入 HelloWorld 会话 bean 的直接例子是只使用 @EJBpublic HelloWorld myHello , 这将导致 myHello 通过一个 HelloWorld bean 实例注入。

  可以使用依赖注入来查找任何类型的环境和资源引用 , 如 DataSource 、 JMS 、 Mail 、 Web 服务 等。

容器外的可测试性和可用性

  当前 EJB 开发人员所关心的一个主要问题不仅包括 EJB 开发的复杂性 , 还包括测试这一难题。开发和测试EJB离不开EJB容器,开发人员也必须熟悉最终的部署平台,才能进行测试。对于很多企业开发人员而言,这可能不是主要问题。但对于为多个供应商提供支持的ISV而言,这的确是个问题,他们必须维护多个环境以测试其EJB。EJB 3.0规范承诺要提供在容器外进行测试的能力,但目前在规范的草案中并没有提到细节。

结束语

  尽管遗漏了很多包装、组装以及 API 的细节信息 , EJB 3.0 草案中的提议仍然对企业 Java 开发人员充满了诱惑。把这些工作留给容器供应商来做,将有助于减少开发人员面对的复杂问题。这就要看容器供应商如何实施这些工作,并使EJB 3.0成为开发企业应用程序的必然之选了。    

相关文章
|
Java 数据库连接 数据库
探索Java中的MyBatis Plus:简化持久层开发的利器
在现代软件开发中,持久层是一个不可或缺的部分。为了更高效地操作数据库,开发者们经常使用ORM(对象关系映射)工具来简化数据库交互。而在Java领域,MyBatis Plus正是这样一个备受欢迎的ORM工具,它通过提供一系列便捷的特性,极大地简化了持久层的开发。本文将深入探讨MyBatis Plus的特点以及如何在项目中使用它。
123 0
|
开发框架 Java 中间件
【中间件】——EJB学习总结
公共服务框架:支持大量的、由应用服务器提供的系统级服务
|
XML Java 数据格式
Spring纯注解开发模式让开发简化更简化
Spring纯注解开发模式让开发简化更简化
146 0
|
SQL 前端开发 Java
Sprig框架集成(SSM框架) | Sping+SpringMVC+Mybatis
SSM是sping+springMVC+mybatis集成的框架:标准的MVC模式,整个系统划分为表现层,controller层,service层,DAO层四层
132 0
|
Java 应用服务中间件 Spring
【EJB学习笔记】——建立一个简单的EJB应用
 这里创建一个简单的EJB应用,结构如下:
【EJB学习笔记】——建立一个简单的EJB应用
|
Java 程序员 容器
选择使用Spring框架的原因(Spring框架为企业级开发带来的好处有哪些)?
可以从以下几个方面作答: 非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。 IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。
1065 0
|
Java 数据库连接 数据处理
|
IDE Java 开发工具
|
Java 应用服务中间件 数据安全/隐私保护