企业级JavaBean(Enterprise JavaBean, EJB)是一个用来构筑企业级应用的服务器端可被管理组件。

Java企业版API(Java Enterprise Edition)中提供了对EJB的规范。EJB是一个封装有某个应用程序之业务逻辑服务器端组件。EJB最早于1997年由IBM提出,旋即被太阳微系统采用并形成标准(EJB 1.0 和EJB 1.1)。其后在Java社区进程(Java Community Process)支持下陆续有一些JSR被制订来定义新的EJB标准,分别是JSR 19 (EJB 2.0), JSR 153 (EJB 2.1) 以及最新的JSR 220 (EJB 3.0)。

历史从拥抱到抛弃由于IBM和Sun Microsystems等EJB提倡者力推其前景,起初一些大公司纷纷采用EJB部署他们的系统。然而随后各种问题便接踵而至,对EJB的恶评短时间内激增。对于初学者,EJB的API显得太过困难;对于许多程序员来说,书写那些必须抛出特定异常的接口并将bean类作为抽象类实现的做法既不直观也不正常。当然,EJB所被赋予的使命,如对象关系映射和事务管理确实有其天然复杂性,但其API之复杂还是令开发人员们觉得望而却步,一些人开始怀疑EJB除了引入了复杂的实现手段以外似乎并未带来什么实际好处。

另外,实际运用中被发现,如果使用EJB来封装业务逻辑会带来性能上的下降。这是因为,最早的EJB规范只允许客户端通过特定协议(如CORBA)进行远程方法调用来调用,即使大部分实际应用根本就不需要分布式计算。直到EJB 2.0才引入了本地接口,以支持可以开发不通过网络就能直接本地调用的EJB系统。

尽管如此,EJB的广泛普及仍然为其复杂度所制约。尽管已经有一些高质量的集成开发工具可以协助开发人员通过自动编码解决一部分重复作业,但这并不能降低学习此项技术的难度。另一方面,“草根阶层”的编程爱好者们发起了一场旨在使用 “轻量级”技术以代替复杂的EJB的运动。这些技术包括Hibernate(用于提供数据持久化和对象-关系映射)及Spring框架(用于封装业务逻辑)。尽管它们不像EJB那样有巨头支持,但其在庶民间却更加流行,并且也被一些对EJB深感失望的企业所采用。

重生EJB规范起初的一个主要价值—对分布式应用进行事务管理—在随后的实践中被一致认为几乎没能派上用场。对于企业级应用来说,Spring和Hibernate等简化框架更加实用。因此,EJB 3.0规范(JSR 220)为了迎合这个趋势相比于其前辈进行了一次激进的大跳跃。受到Spring 影响,EJB 3.0也使用所谓的“传统简单Java对象(POJO)”;同时,支持依赖注入来简化全异系统的集成与配置。Hibernate的创始人Gavin King参与了这一新版规范的制订,并对EJB大加提倡。Hibernate的许多特性也被引入到Java持久化API当中,从而取代原来的实体bean。EJB 3.0规范大幅采用Java注释(annotation)来对代码进行元数据修饰,从而消减了此前EJB编程的冗杂性。

相应地,EJB 3.0几乎成为了一个全新的API,与此前的数版可谓毫无相似度可言1。

EJB种类EJB容器可以接受三类EJB

会话Bean(Session Beans)

无状态会话Bean(Stateless Session Beans)

有状态会话Bean(Stateful Session Beans)

实体Bean(Entity Beans)

消息驱动Bean(Message Driven Beans ,MDBs)

无状态会话Bean是一类不包含状态信息的分布式对象,允许来自数个客户端的并发访问。实例变量的内容在前后数次呼出中不被保留(确切地说是不保证保留)。由于不必控制与用户间的对话信息而减少了开销,无状态会话Bean不像有状态会话Bean那样具有资源集约性。举例来说,一个发送邮件的EJB就可被设计为一个无状态会话Bean。在整个会话期,用户只向服务器提交一个动作:发送指定邮件到指定地址。(称为开关行为)

有状态会话Bean是包含状态的分布式对象,即是说,贯穿整个会话它们都要保有客户端信息。举例而言,在一个网上商店进行实施结账很可能就需要一个有状态会话Bean,因为结账是一个多步动作,服务器端必须可以随时了解到用户已经进行到了哪一步。此外,尽管有状态会话Bean的状态信息可被保持,但始终只能是由同一个用户来访问之。

实体Bean是含有持久化状态的分布式对象。这个持久化状态的管理既可以交给Bean自身(Bean-Managed Persistence,BMP),也可以托付于外部机制(Container-Managed Persistence,CMP)。

消息驱动Bean是支持异步行为的分布式对象。它们并不对请求进行当即响应。比方说,某网站用户点击“请通知我更新信息”按钮,将会触发某个MDB将这名用户加入到数据库的希望获得更新信息用户列表中。这个动作就是一个异步的消息驱动过程,因为用户不必等待当时会返回某个结果。MDB的消息源来自Java消息服务(JMS)提供的消息队列或消息主题。自EJB 2.0规范起,JMS被加入进来以允许在容器内部实施事件驱动处理。与其他EJB不同,MDB不存在一个用户视图(如需要用户引用的远程接口),用户也不能通过资源定位获得一个MDB实例。MDB只在后台监听消息源并实施自动处理。

除了上述以外,当前还有一些EJB处于设想阶段,如JSR 86提出了用于在Java EE应用中集成多媒体对象的媒体Bean(Enterprise Media Beans)。

EJB实行EJB部署于应用服务器端的EJB容器中。规范给定了EJB与EJB容器之间,以及用户代码与EJB/EJB容器之间的交互方式。对于Java EE API,javax.ejb包定义了EJB类,javax.ejb.spi包定义了EJB容器应当实现的各个接口。

在EJB 2.1和以前的版本中,每个EJB都由一个类和两个接口组成。EJB容器负责创建这个类的实例,接口则供客户端调用。

两个接口分别被称为Home接口和组件接口,负责提供各个EJB远程方法声明。这些EJB远程方法可分成两组:

类方法:由Home接口提供。与特定实例无关,仅负责一些公共内容,比如创建一个新的EJB实例(create方法),或寻找一个已经存在的EJB实例(find方法)等等。

接口方法:由组件接口提供的针对特定实例的业务方法。

EJB容器将为这些接口提供对应的实现类以充当客户远程代理,当客户端调用这个生成的代理类的某个方法时,代理类内部会将此调用的方法和参数封装成一个消息发送给服务器。服务器收到消息后在转发给真实的EJB实例,后者负责执行真正的业务逻辑。

远程通信EJB规范要求EJB容器能够支持基于RMI-IIOP的EJB访问。EJB既可被任何CORBA应用访问,也能提供Web服务。

事务EJB容器必须支持符合ACID(原子性/一致性/独立性/持久性)特性的容器级事务管理,以及bean内部事务管理。容器级事务需在部署描述符中(EJB应用的配置文件)进行声明。

事件EJB使用JMS向客户对象发送消息,客户则可以异步地接受这些消息。MDB则接受来自客户端的消息。

命名和目录服务EJB客户端使用JNDI或CORBA名字服务定位Home接口实现 对象。通过此Home接口,用户还可以寻找,创建或删除实体对象。

安全EJB容器对客户端的访问权限负责。

部署EJBEJB规范还定义了一个跨平台的统一部署机制。部署描述符中定义了关于EJB应用的一切相关内容。文件名通常为ejb-jar.xml。

部署描述符是一个XML文档,负责为该EJB应用中的每一个EJB定义入口。部署描述符的主要内容包括:

Home接口名

Bean的Java类名

Home接口的Java接口名

组件接口的Java接口名

持久化存储(针对实体Bean)

安全策略和角色分配

通常EJB容器提供者还定义了一些额外的XML或其他格式描述文件来强化其容器的功能。他们还同时提供这些描述文件的解读工具类和对Home接口的自动实现类生成。

EJB3.0起开始广泛使用Java注释替代传统的部署描述符ejb-jar.xml。但后者仍然有效。

版本变化EJB 3.02006年5月2日发布,JSR 220定义。

全面采用Java注释代替部署描述符。(后者仍可使用,并且具有更高优先级)

把2.X版的EntityBean改为由JPA支持。

EJB 2.12003年11月24日发布,JSR 153定义。

Web服务:可将无状态会话bean暴露为Web服务;EJB可通过引用访问Web服务。

EJB定时器服务:提供一种新的基于定时器的事件驱动方式。可供消息驱动bean作为消息源使用。

增加了消息目的地。

进一步丰富了EJB查询语言,支持ORDER BY, AVG, MIN, MAX, SUM, COUNT和MOD。

使用XML schema代替DTD以定义部署描述符。

EJB 2.02001年8月22日发布,JSR 19 定义。

制定了构建面向对象商务应用的标准组建结构。

支持构筑使用不同开发工具所开发之组件的联合应用部署。

在多线程,连接池,事务管理等方面对用户透明化。

使符合“一次写成,多次运行”的Java思想。

关注企业级应用生命期间的开发,部署,运行等动作。

定义了不同开发工具所需遵守的契约,以便其产品能够在运行期交互。

支持与现行系统兼容,开发者可以扩展现有产品以使之支持EJB。

与其他Java API兼容。

支持EJB与Java2平台企业版或者其他非Java应用程序之间的互操作性。

支持与CORBA兼容的RMI-IIOP。

EJB 1.1999年12月17日发布。

开始采用XML部署描述符,默认的JNDI上下文以及可支持IIOP的RMI。

安全机制由角色(Role)驱动,而非方法。

支持实体类,且必须在应用中实现。

EJB 1.01998年3月24日发布。

定义了EJB和EJB容器的作用,实现与互动。

提供了最早的开发者与用户视图。

简介1.SessionBean用于实现业务逻辑,它可以是有状态的,也可以是无状态的。每当客户端请求时,容器就会选择一个SessionBean来为客户端服务。Session Bean可以直接访问数据库,但更多时候,它会通过Entity Bean实现数据访问。

2.Entity Bean是域模型2对象,用于实现O/R映射,负责将数据库中的表记录映射为内存中的Entity对象,事实上,创建一个Entity Bean对象相当于新建一条记录,删除一个Entity Bean会同时从数据库中删除对应记录,修改一个Entity Bean时,容器会自动将Entity Bean的状态和数据库同步。

3.MessageDriven Bean是EJB2.0中引入的新的企业Bean,它基于JMS消息,只能接收客户端发送的JMS消息然后处理。MDB实际上是一个异步的无状态SessionBean,客户端调用MDB后无需等待,立刻返回,MDB将异步处理客户请求。这适合于需要异步处理请求的场合,比如订单处理,这样就能避免客户端长时间的等待一个方法调用直到返回结果。

EJB实际上是SUN的J2EE中的一套规范,并且规定了一系列的API用来实现把EJB概念转换成EJB产品。

EJB一个技术规范:EJB 从技术上而言不是一种"产品",EJB 是一种描述了构建应用组件要解决的标准:

可扩展 (Scalable)

分布式 (Distributed)

事务处理(Transactional)

数据存储(Persistent)

安全性 (Secure)

期望提供一个标准的分布的、基于OO的组件架构

屏蔽复杂的系统级功能需求

Write once, run anywhere

与非 Java应用之间的互操作能力

兼容CORBA标准

选择EJBEJB 服务器完成"繁杂"的工作:应用开发人员关注于业务逻辑的实现而不是底层的实现机制(类似于4GL语言设计的目标)

支持事务处理

多个业务操作同时成功,或全部失败

可以通过在代码外的描述来定义事务处理级别可扩展性

EJB 可以根据您应用的增长而扩展

EJB 服务器往往还提供了负载均衡

安全性:由 EJB 服务器提供资源的访问权限控制

EJB 架构为了满足架构的目标,规范中描述了

服务器 (Server)

容器(Container)

类 (Class) 和实例 (Instance)

Home 和 Remote 接口

客户端(Client)

编程模型关注于业务逻辑实现:EJB 负责生命周期 (lifecycle),数据存储(persistence), 事务处理语义 (transactional semantic), 安全(security), ...

通用的编程模型:各种服务的高层API

Java 是其编程语言

EJB( 业务逻辑代码 ) 表示了与特定商业领域(例如银行、零售等行业)相适应的逻辑。它由

运行在业务逻辑层的 enterprise bean 处理。一个 enterprisebean 可以从客户端接受数据,对

它进行处理,并将其发送到企业信息系统层以作存储;同时它也可以从存储器获取数据,

处理后将其发送到客户端应用程序。

有三种类型的 enterprise javabeans:session beans、entity beans 和 message-driven beans。

Session bean 描述了与客户端的一个短暂的会话。当客户端的执行完成后,session bean 和

它的数据都将消失;与之相对应的是一个 entity bean 描述了存储在数据库表中的一行持久

稳固的数据,如果客户端终止或者服务结束,底层的服务会负责 entity bean 数据的存储。

Message-driven bean 结合了 session bean 和 Java信息服务(JMS)信息监听者的功能,它允

许一个商业组件异步地接受 JMS消息。

EJB3.0由于EJB2.0的复杂性,在Spring和Hibernate2等轻量级框架出现后,大量的用户转向应用轻量级框架。在大家的呼声中,期待已久的EJB3.0规范终于发布了。在本文中将对新的规范进行一个概要性的介绍,包括新增的元数据支持,EJBQL的修改,实体Bean模型访问bean上下文的新方法和运行时环境等等。作者还讨论了EJB在未来要作出的调整以及EJB3.0与其他开发规范之间的关系。

开始无论如何由于EJB的复杂性使之在J2EE架构中的表现一直不是很好。EJB大概是J2EE架构中唯一一个没有兑现其能够简单开发并提高生产力承诺的组件。EJB3.0规范正尝试在这方面作出努力以减轻其开发的复杂性。EJB3.0减轻了开发人员进行底层开发的工作量,它取消或最小化了很多(以前这些是必须实现)回调方法的实现,并且降低了实体Bean及O/R映射模型的复杂性。

在本文中,我首先会介绍EJB3.0中几个主要的改变。它对进一步深入了解EJB3.0是非常重要的。随后,我会从更高的层面来描述已经被提交到EJB3.0规范中的细节,并一个个的讲解新的规范中的改变:实体Bean,O/R映射模型,实体关系模型和EJB QL(EJB查询语言)等等。

背景EJB3.0中两个重要的变更分别是:使用了Java5中的程序注释工具和基于Hibernate的O/R映射模型。Java5中的元数据工具

Java5(以前叫J2SE1.5或Tiger) 中加入了一种新的程序注解工具。通过这个工具你可以自定义注解标记,通过这些自定义标记来注解字段、方法、类等等。这些注解并不会影响程序的语义,但是可以通过工具(编译时或运行时)来解释这些标记并产生附加的内容(比如部署描述文件),或者强制某些必须的运行时行为(比如EJB组件的状态特性)。注解的解析可以通过源文件的解析(比如编译器或这IDE工具)或者使用Java5中的APIs反射机制。注解只能被定义在源代码层。由于所有被提交到 EJB3.0草案中的注解标记都有一个运行时的RetentionPolicy,因此会增加类文件占用的存储空间,但这却给容器制造商和工具制造商带来了方便。

Hibernate

框架,目的是把开发人员从繁琐的数据持久化编程中解脱出来。它也有一个标准的HQL(Hibernate 查询语言)语言,你可以在新的EJB QL中看到它的影子。Hibernate在处理如数据查询、更新、连接池、事务处理、实体关系处理等方面非常简单。

概览在已经提交的EJB3.0规范中主要涉及两个方面的改变:

1. 一套以注释为基础的EJB编程模型,再加上EJB2.1中定义的通过部署描述符和几个接口定义的应用程序行为。

2. 新的实体Bean持久化模型,EJBQL也有许多重要的改变。

还有一些有关上述的提议,比如:一个新的客户端编程模型,业务接口的使用以及实体Bean的生命周期。请注意EJB2.1编程模型(包括部署描述符和home/remote接口)仍然是有效的。新的简化模型并没有完全取代EJB2.1模型。

注解EJB规范组织一个重要的目标是减轻原始代码的数量,并且他们为此给出了一个完美而简洁的办法。在EJB3.0的里,任何类型的企业级 Bean只是一个加了适当注解的简单Java对象(POJO)。注解可以用于定义bean的业务接口、O/R映射信息、资源引用信息,效果与在 EJB2.1中定义部署描述符和接口是一样的。在EJB3.0中部署描述符不再是必须的了;home接口也没有了,你也不必实现业务接口(容器可以为你完成这些事情)。

比如,你可以使用@Stateless注解标记类把Java类声明为一个无状态会话bean。对于有状态会话bean来说,@Remove注释可以用来标记一个特定的方法,通过这个注解来说明在调用这个方法之后bean的实例将被清除掉。

为了减少描述组件的说明信息,规范组织还采纳了由异常进行配置(configuration-by-exception)的手段,意思是你可以为所有的注解提供一个明确的缺省值,这样多数常规信息就可以据此推断得出。

持久化模型新的实体bean也是一个加了注释的简单Java对象(POJO)。一旦它被EntityManager访问它就成为了一个持久化对象,并且成为了持久化上下文(context)的一部分。一个持久化上下文与一个事务上下文是松耦合的;严格的讲,它隐含的与一个事务会话共存。

实体关系也是通过注释来定义的,O/R映射也是,并提供几种不同的数据库规范操作,在EJB2.1中这些要通过开发人员自己的设计模式或者其它技术来完成的(比如,自增长主键策略)。

深入研究

是时候详细了解EJB3.0草案了。让我们开始探讨所有EJB中四种企业级bean,并看看他们在新的规范中是什么样子。

bean在EJB3.0规范中,写一个无状态会话bean(SLSB)只需要一个简单的Java文件并在类层加上@Stateless注释就可以了。这个bean可以扩展javax.ejb.SessionBean接口,但这些不是必须的。

一个SLSB不再需要home接口,没有哪类EJB再需要它了。Bean类可以实现业务接口也可以不实现它。如果没有实现任何业务接口,业务接口会由任意public的方法产生。如果只有几个业务方法会被暴露在业务接口中,这些方法可以使用@BusinessMethod注释。缺省情况下所有产 生的接口都是local(本地)接口,你也可以使用@Remote注释来声明这个接口为remote(远程)接口。

下面的几行代码就可以定义一个HelloWorldBean了。而在EJB2.1中同样的bean至少需要两个接口,一个实现类和几个空的实现方法,再加上部署描述符。

import javax.ejb.*;

/**

* A stateless session bean requesting that a remote business

* interface be generated for it.

*/

@Stateless

@Remote

public class HelloWorldBean {

public String sayHello() {

return "Hello World.";

}

}

有状态会话除了几个SFSB的特别说明之外,有状态会话bean(SFSB)和SLSB一样精简:

一个SFSB应该有一个方法来初始化自己(在EJB2.1中是通过ejbCreate()来实现的)。在EJB3.0的规范中建议这些初始化操作可以通过自定义方法完成,并把他们暴露在业务接口中。在使用这个bean之前由客户端来调用相应的初始化方法。规范组织就是否提供一个注释来标记某个方法用于初始化还存在争议。

Bean的提供者可以用@Remove注释来标记任何SFSB的方法,以说明这个方法被调用之后bean的实例将被移除。同样,规范组织仍然在讨论是否要有一种机制来处理这种特殊的情况,即当这个方法出现异常的情况下bean的实例是否被移除。

下面是对以上问题我个人的观点:

是否应该有一个注释来标明一个方法进行初始化呢?我的观点是――应该有,这样容器就可以在调用其他方法之前至少调用一个方法来进行初始化。这不仅可以避免不必要的错误(由于没有调用初始化方法)而且可以使容器更明确的判断是否可以重用SFSB实例。我暂且把这个问题放一放,规范组织只考虑为一个方法提供一个注释来声明它是一个初始化方法。

对于第二个问题我的观点也是肯定的。这有利于Bean的提供者合客户端程序对其进行控制。只有一个遗留的问题:那就是一旦调用这个方法失败,是否能移除这个bean 的实例?答案是不能,但是它将会在会话结束的时候被移除。

消息驱动消息驱动Bean是唯一一种必须实现一个业务接口的Bean。这个接口指出bean支持的是哪一种消息系统。对于以JMS为基础的MDB来说,这个接口是javax.jms.MessageListener。注意MDB业务接口不是一个真正意义上的业务接口,它只是一个消息接口。

JMS综述1.JMS简介

JMS是Java消息服务(Java Message Service)的简写,是由SUN公司开发的一个开放性的应用编程接口(API),包含在javax.jms.*包中。

JMS对象模型如图所示。

JMS对象模型包含如下几个要素:

1)连接工厂。连接工厂(ConnectionFactory)是由管理员创建,并绑定到JNDI树中。客户端使用JNDI查找连接工厂,然后利用连接工厂创建一个JMS连接。

2)JMS连接。JMS连接(Connection)表示JMS客户端和服务器端之间的一个活动的连接,是由客户端通过调用连接工厂的方法建立的。

3)JMS会话。JMS会话(Session)表示JMS客户与JMS服务器之间的会话状态。JMS会话建立在JMS连接上,表示客户与服务器之间的一个会话线程。

4)JMS目的。JMS目的(Destination),又称为消息队列,是实际的消息源。

5)JMS生产者和消费者。生产者(Message Producer)和消费者(Message Consumer)对象由Session对象创建,用于发送和接收消息。

6)JMS消息通常有两种类型:

① 点对点(Point-to-Point)。在点对点的消息系统中,消息分发给一个单独的使用者。点对点消息往往与队列(javax.jms.Queue)相关联。

② 发布/订阅(Publish/Subscribe)。发布/订阅消息系统支持一个事件驱动模型,消息生产者和消费者都参与消息的传递。生产者发布事件,而使用者订阅感兴趣的事件,并使用事件。该类型消息一般与特定的主题(javax.jms.Topic)关联。

2.消息驱动Bean简介

消息驱动Bean MDB(Message Driven Bean)是EJB 2.0规范中添加的EJB组件规范,它兼备EJB和JMS的功能。JMS和消息Bean的调用关系如图26-23所示。

MDB被部署为总是充当消息消费者的角色,并且与特定的JMS目的相关联,MDB从JMS目的(队列或主题)接收消息生产者发送的消息。

与会话Bean和实体Bean不同的是,消息驱动Bean不需要定义远程接口和Home接口,也不能被客户端直接调用。

实体Bean实体Bean使用@Entity注释来标记,所有实体bean中的属性/字段不必使用@Transient注释来标记。实体bean的持久化字段可以通过JavaBean-style机制或者声明为public/protected字段来实现。

实体bean可以使用助手类来描述其状态,但是这些类的实例并没有持久化唯一性(persistent identity)的特性(即,唯一标识这个bean的字段等),实际上这些助手类与他们的实体bean实例是紧密结合的;并且这些对象还是以非共享方式来访问实体对象的。

实体关联EJB3.0同时支持Bean之间双向的和单向的关联,它们可以是一对一、一对多、多对一或者是多对多的关联。然而双向关联的两端还要分为自身端 (owning side)和对方端(inverse side)不同的端。自身端负责向数据库通告关联的变更。对于多对多的关联自身端必须明确的声明。实际上对方端通过isInverse=true进行注释 (由此自身端就不必说明了而是由另一段推断出)。看来上面的描述,规范组织还能说让EJB变的简单了吗?

O/R映射EJB3.0中的O/R映射模型也有了重要的改变,它从原来的abstract-persistence-schema-based变成了现在的Hibernate-inspired模式。尽管规范组织还在就此进行讨论但是一个明确的模型将会出现在下一个版本的草案中。

举例来说,O/R映射模型将通过bean类中的注释来声明。而且此方法还会指出对应的具体表和字段。O/R映射模型提供了一套自有的SQL; 而且除了提供一些基本的SQL外还支持某些高层开发的功能。比如,有一个通过@Column注释声明的字段columnDefinition,那么可以写这样的SQL:columnDefinition="BLOB NOT NULL"

客户端一个EJB客户端可以通过@Inject注释以一种“注入”的方式获得一个bean的业务接口引用。你也可以使用另一个注释 @javax.ejb.EJBContext.lookup()来完成上面的操作,但是规范中没有告诉我们一个普通的Java客户端怎样获得一个Bean 的实例,因为这个普通的Java客户端是运行在一个客户端容器中,它无法访问@javax.ejb.EJBContex对象。

EJB QLEJB QL可以通过@NamedQuery来注释。这个注释有两个成员属性分别是name和queryString.一旦定义了这些属性,就可以通过 EntityManager.createNamedQuery(name)来指向这个查询。你也可以创建一个标准的JDBC风格的查询并使用 EntityManager.createQuery(ejbqlString)或EntityManager.createNativeQuery (nativeSqlString)(这个方法用于执行一个本地查询)来执行查询。

EJB QL有两个地方可以定义其参数。javax.ejb.Query接口提供了定义参数、指向查询、更新数据等等方法。下面是一个EJBQL指向查询的例子:

查看复制到剪切板打印

. ..

;@NamedQuery(

name="findAllCustomersWithName",

queryString="SELECT c FROM Customer c WHERE c name LIKE :custName"

)

.. ..

;@Inject public EntityManager em;

customers = em.createNamedQuery("findAllCustomersWithName")

.setParameter("custName", "Smith")

.listResults();

下面列出了一些EJB QL的增强特性:

支持批量更新和删除。

直接支持内连接和外连接。FETCH JOIN运行你指出关联的实体,Order可以指定只查询某个字段。

查询语句可以返回一个以上的结果值。实际上,你可以返回一个依赖的类比如下面这样:

SELECT new CustomerDetails(c id, c.status, o.count)

FROM Customer c JOIN c.orders o

WHERE o.count > 100 l 支持group by 和having。

子查询在提交的EJB3.0草案中,EJB QL与标准SQL非常的接近。实际上规范中甚至直接支持本地的SQL(就像我们上面提到的那样)。这一点对某些程序员来说也许有些不是很清楚,我们将在下面进行更详细的讲解。

多样性方法许可(Method permissions)可以通过@MethodPermissions和@Unchecked注释来声明;同样的,事务属性也可以通过 @TransactionAttribute注释来声明。规范中仍然保留资源引用和资源环境引用。这些一样可以通过注释来声明,但是有一些细微的差别。比如,上下文(context)环境要通过注入工具控制。容器根据bean对外部环境引用自动初始化一个适当的已经声明的实例变量。比如,你可以像下面这样获得一个数据源(DataSource):

;@Resource(name="myDataSource") //Type is inferred from variable

public DataSource customerDB;

在上面的例子中如果你不指定引用资源的名称(name)那么其中的customerDB会被认为是默认值。当所有的引用属性都可得到时候@Injec注释就可以这样写:

查看1. ;@Inject public DataSource customerDB;

;@Inject public DataSource customerDB;

容器负责在运行时初始化customerDB数据源实例。部署人员必须在此之前在容器中定义好这些资源属性。

更好的消息是:那些以前必须检测的异常将一去不复返。你可以声明任意的应用程序异常,而不必在再抛出或捕获其他类似 CreateException和FinderException这样的异常。容器会抛出封装在javax.ejb.EJBException中的系统级异常或者只在必要时候抛出IllegalArgumentException或IllegalStateException异常。

处理模式在我们结束本节之前,让我的快速的浏览一下容器提供商在EJB处理模式方面可能的变更。规范中对此并没有明确的表态,但我可以想到至少两种模式。

一种办法是首先利用EJB文件生成类似于EJB2.1部署模式的文件(包括必要的接口和部署描述符)然后再用类似于EJB2.1的方式来部署这个EJB组件。当然,这样产生的部署描述符可能并不标准但是它可以解决同一个容器对EJB2.1和EJB3.0兼容的问题。下面这幅图描述了这一过程。

另一种方法是一种类似于JSP托放的部署模式。你可以把一个EJB文件放到一个预先定义的目录下,然后容器会识别这个EJB并处理它,然后部署并使之可以使用。这种方法可以建立于上面那种方法之上,在支持反复部署时有很大的帮助。考虑到部署的简单性也是EJB3.0规范的目的之一,我真诚的希望在下一个草案出来时能够确定一个模式(至少能有一个非正式的)。

你有什么想法?

EJB3.0规范的制定正在有序的进行,为了使EJB的开发变得更加容易,EJB规范组织作出的努力是有目共睹的。就像他们说的那样,一切对会变得简单,但做到这一点并不容易。已经定义了50个注释标记(还有几个将在下一个草案中发布),每一个都有自己的缺省规则和其他的操作。当然,我真的不希望EJB3.0变成EJB2.1的一个翻版"EJB 3.0 = EJB 2.1 for dummies"(希望这个等式不要成立)。最后,我还是忍不住要提一些我自己的观点:

首先,规范确实使反复部署变得容易了,并且有一个简单的模式来访问运行时环境。我还是觉得home接口应该放弃。

在早期的EJB规范中,实体bean用于映射一个持久化存储。理论上(也许只是理论上)可能需要把实体bean映射到一个遗留的EIS (enterprise information system)系统中。出于将来扩展的考虑这样作是有好处的,并且可以使更多的业务数据模型采用实体bean。也因此其伴随的复杂性使得实体bean不被看好。在本次提交的草案中,一个实体bean只是一个数据库的映射。并且是基于非抽象持久化模式和简单的数据访问模式的更加简单开发。

我对模型变更持保留态度,我认为在EJB中包含SQL脚本片断并不是个好注意。一些开发人员完全反对包含某些“SQL片段 (SQLness)”(比如@Table 和 @Column注释)。我的观点是这些SQLness是好的,据此我们可以清楚的知道我们到底要数据库作些什么。但是某些SQL段我看来并不是很好,比如 columnDefinition="BLOB NOT NULL",这使得EJB代码和SQL之间的耦合太过紧密了。

尽管对于本地SQL的支持看似很诱人,其实在EJB代码中嵌入SQL是一个非常糟糕的主意。当然,有些办法可以避免在EJB中硬编码SQL,但是这应该在规范中说明,而不能是某些开发人员自己定义的模式。

假设@Table注释只用于类。在运行时通过@Table注释的name属性定义的表名称将必须对应一个实际的数据库表。规范对此应该给予清楚的说明和一致的模式。

规范还需要更清楚的说明客户端编程模型,尤其是普通java客户端。规范中所有的参考都假设或者隐含的使用EJB客户端。而且规范中对客户端的向后兼容方面也没有给出明确的说法。

Transient注释应该重新命名以避免和已有的transient关键字发生冲突。事实上,在这一点上我们更乐于稍微的背离一下 configuration-by-exception原则并且定义一个@Persistent注释来明确的定义持久化字段 @Persistent注释 可以仅仅是一个标记注释或者它可以有几个属性来关联O/R映射注释。

关联可能影响到EJB3.0的JSR有JSR175(java语言元数据工具)和JSR181(Java Web服务元数据)

JSR175已经初步完成并且不会和EJB3.0有太大的冲突;但是JSR181与EJB3.0有两个关联的地方:

Web service接口:EJB规范将采用一种机制适应JSR181以便可以把一个bean实现为一个Web service并告诉Web service如何被客户端调用。

JSR 181计划采用不同的机制来处理安全问题。在早期的规范中EJB建议使用一个一致的机制(MethodPermissions),但是JSR 181计划使用一个稍微不同的方式(SecurityRoles和SecurityIdentity注释)。同样的RunAs注释的定义也存在这些许差别。这一问题还在解决中最终会在J2EE层的规范中维持其一致性。

在J2EE 1.5中的一些开发规范可能与EJB3.0有关联。除了上面说到的几个关联之外现在没有其他的开发规范与EJB3.0有冲突。

EJB3.1对于EJB,优先考虑的就是全部重建。“我们只有先清空杯子里的水,才能接纳新的东西”。杯子已经清空了,这对我们来说是非常有利的,而且还可以没有包袱的大胆前进。

EJB3.1 又一次引入了一系列新的特性,倾向于挖掘技术的潜力。依我来看,EJB3.1绝对是一个重要的发布版本,它将那些长期让人渴望的特性带到开发者面前,更加能够满足最新的企业应用程序开发,同时对EJB再次被人们采纳将做出巨大的贡献。

EJB 3.1 最终发行版已经发布了。

EJB3.1架构模式相对于旧的架构模式有如下的一些扩展和针对API的一些简化:

· 简化的本地模式让去除了本地的商务接口一样可达到session bean

· 直接用war文件打包一个ejb组件不需要一个ejb-jar

· 在Java SE环境中嵌入API执行EJB

· 引入了可以提供简单的共享应用数据和支持一致性访问的Singleton session bean组件

· 自动创建EJB定时器

· 基于EJB定时表达式的日程表

· 异步session bean调用

· 对于一个EJB轻量子集的定义,这个子集可以提供一些Java EE文档 (EJB lite)

· 一个用来查询ejb组件的Global JNDInames( 统一的 全局 JNDI 命名 ) 规则

结束语在使EJB的开发变得简单高效之前,我们还有很长一段路要走。规范组织在降低EJB的开发难度方面起了个好头。O/R映射模型的提议还处在早期阶段,规范组织正在完善它。我希望它不要太复杂也不要与SQL过分的耦合。

本词条内容贡献者为:

闫晓东 - 副教授 - 中央民族大学信息工程学院

来源: 百度百科