Simplifying EJB Development with EJB3.0
使用EJB3.O简化EJB开发
October 2004
Enterprise JavaBeans (EJB) was introduced for building distributed components. When it arrived it came with a promise to solve all issues and complexities of CORBA. EJB being the heart of J2EE went through several major revisions and got fattened with many features. Early on, most of the developers fell in love with EJB and used EJB in their application even it did not make any sense. “Blame it on EJB” has been the attitude for many developers when their projects did not scale well and they used EJB.
我们引入EJB来构造分布式的组件。它诞生之时是为了解决所有CORBA的问题和复杂性。经历过几次重要的版本更新和增加许多特性之后,EJB已经成为了J2EE的核心。在早期,很多开发人员沉迷于EJB甚至在没有任何意义的情况下在他们的工程中使用EJB。而当他们发现所使用的工程并没有质的变化后,谴责EJB成了一种趋势。
Development of EJB was never easier and it became more complex with every release of EJB specification. EJB has been compared with an elephant due to its complexity and heavy weight nature. Many developers feel EJB is like an extra layer of sugar syrup on a doughnut. In an age where low carb and Atkins diet is craze, the EJB expert committee has no option but to produce a low carb incarnation of EJB thus simplifying the development of EJB. EJB 3.0 expert committee released a sample picture of the lightweight model during JavaOne 2004 when it announced release of first public draft of EJB 3.0 Specification.
开发EJB从来没有变得简单甚至在早期的EJB版本规范中变得更加复杂。EJB由于其的复杂性和重量级特性而被比作一只大象。学多开发人员感觉EJB象一个油炸圈饼上多余的一层甜糖浆。在现在low carb和Atkins diet大行其道的今天,EJB专家委员会也没有选择余地的发布了体现low carb的EJB规范来简化EJB的开发。EJB3.0专家委员会在2004Javaone大会上发布了称之为EJB3.0第一个公开规范的轻量级模型的范例图。
At the first glimpse the new model for EJB looks pretty and in this article we will discuss how EJB 3.0 is trying to dress up in a smaller size pretty outfit to make it appealing for developers. In a follow up article we will discuss how EJB 3.0 is simplifying the persistence model.
第一眼看到EJB的新模型感觉很不错。在这篇文章中我们将讨论EJB3.0如何使用一个更小而精致的装配来吸引开发者的。在接下来的文章中我们将来讨论EJB3.0是怎样简化持久性模型的。
Cleaning up the Dirty Laundry整理缺陷
Let us look at the complexities in the current EJB model before we dive down discussing the details what EJB 3.0 is bringing on to the table.
在我们开始对EJB3.0带来的新特性进行讨论之前,让我们先分析一下现在EJB模型的复杂繁琐。
The current EJB model requires creation of several component interfaces and implementation of several unnecessary callback methods.
现在的EJB模型需要建立许多组件接口和实现许多不必要的回滚方法。
The component interfaces require implementation of EJBObject or EJBLocalObject and handling of many unnecessary exceptions is required.
组件接口需要实现EJBObject或者EJBLocalObject,并且处理许多不必要的异常。
The EJB deployment descriptor is complex and error prone.
EJB的部署描述复杂而容易出错。
The container managed persistence being based on the EJB model is again overly complex to develop and manage. There are several basic features missing such as a standard way to define a primary key using database sequence and EJBQL is very limited.
基于EJB模型的容器持久化管理的开发和管理过于复杂。许多基础的特征未考虑到,比如使用数据库序列和EJBQL定义一个主键的标准方法就非常有限。
EJB components do not look like its Object Oriented as it has restrictions for using inheritance and polymorphisms.
EJB组件不像是面向对象的,比如在使用继承和多态时就有太多限制。
One major drawback of EJBs is that you cannot test EJB modules outside an EJB container and debugging an EJB inside the container is a nightmare for developers.
一个主要的EJB的缺点是你不能脱离EJB容器测试一个EJB模型且不能在容器内调试一个EJB,这对开发者无疑是一个可怕的事情。
If you used EJB you know the complexities of looking up and invocation of EJB. It appears that you have to know minute details of JNDI to just use an EJB in your application.
如果你使用EJB你需要熟悉调用和查找EJB的复杂过程。显然,你仅仅要在程序中使用EJB但你却必须知道JNDI详细的细节。
Simplifying Developers view简化开发者的观点
If you developed an EJB with the latest specification you realize how difficult is develop a simple EJB like HelloWorld EJB. You need at least two interfaces, a bean class and a deployment descriptor. Most of the developers wondered why do I need all these. IDEs like Oracle JDeveloper, Eclipse and XDoclet made the life simple for developers for doing these mundane tasks however still it was the responsibility of developer to compile these classes and package the deployment descriptor before the EJB can be deployed in your container of choice.
如果你使用现有版本的EJB你会懂得开发一个如HelloWorld的简单的EJB程序是多么困难。你至少需要两个接口,一个bean类和一个部署描述文件。大多数的开发者希望知道为什么我需要所有这些。IDEs(开发环境工具)象Oracle的JDeveloper, Eclipse和XDoclet简化了开发者的做这些普通的工作开发周期,可是在EJB在你部署到所选择的容器中之前,编译类和打包部署文件依然是开发人员的工作。
EJB 3.0 is trying to address the complexities by:
EJB3.0试图从以下方面简化复杂性:
Removing need of interfaces and deployment descriptors and these may be generated by the container using metadata annotations
不必定义接口和部署的描述文件,这些可以由容器使用metadata annotations生成。
Use regular Java classes as EJBs and regular business interfaces for EJBs
使用常用的Java类作为EJB的类和常用的EJB业务接口。
Metadata Annotations 元数据描述
EJB 3.0 depends heavily on metadata annotations. Metadata annotation being standardized under JSR 175 and will be part of J2SE 5.0. Annotation is a kind of attribute oriented programming and similar to XDoclet. However unlike XDoclet that requires pre-compilation, annotations are compiled into the classes (depending upon what the @Retention is set to) by the Java compiler at compile-time. In developer’s point of view, annotations are modifiers like public and can be used in classes, fields, methods, parameters, local variables, constructors, enumerations and packages.You can use annotations in your Java code by specifying attributes that can be used for either generating code, documenting code or providing special services such as enhanced business-level security or special business logic during runtime. The goal of J2EE 1.5 (5.0) is to simplify development using annotations and hence it will come up with its set of annotations. Annotations are marked with @ as follows:
EJB3.0非常倚重Metadata Annotations。Metadata Annotations已经成为JSR 175标准并且将是J2SE 5.0的一部分。Annotations是一种对象变成的属性,非常类似与XDoclet。可是不像XDoclet那样需要预先编译,Annotations由Java编译器在需要编译的时候编译。(依赖于@Retention的开始时间)。在开发人员的观点,Annotations就如同一个公有的并可以作为类,域,方法,参数,本地变量,构造,枚举和包一样使用的修改量。你可以在你的Java代码中附带特殊的属性使用Annotations来生成代码,自动编写文档代码,或者提供如在运行期间增强业务层安全或特殊业务逻辑的特殊服务。J2EE1.5(5.0)的目标是简化开发人员使用Annotations因此而可能产生一套的Annotations模板。Annotations使用@来标记,如下:
@Author("Debu Panda")
@Bean
public class MySessionBean
The goal of EJB 3.0 is to simplify development and hence use metadata annotations to generate several artifacts like interfaces and use annotations instead of deployment descriptors.
EJB3.0为了简化开发因此使用Metadata Annotations来产生许多如接口一样的人为因素和使用Annotations来替代部署描述文件。
Using POJOs and POJIs使用 POJOs 和 POJIs
In canonical terms, JavaBeans and interfaces often referred as Plain Old Java Objects (POJOs) and Plain Old Java Interfaces (POJIs) respectively. The EJB class and interface will now resemble POJO and POJI respectively. The requirement of the unnecessary artifacts like home interface is being removed.
在规范条件中,JavaBeans和接口经常分别的涉及到简单Java对象(POJOs)和简单Java接口(POJIs)。这些不必要的如Home接口的人为因素已经被去掉。
The developer has to either implement one of the EJB interfaces (SessionBean, EntityBean or MessageDrivenBean) in javax.ejb package or use annotation in the bean implementation class. You can either use Stateless, Stateful, MessageDriven or Entity to annotate your bean class. For example, if you define a stateless EJB as HelloWorld you define the EJB as follows:
开发人员必须在javax.ejb包中实现一个EJB接口(会话bean,实体bean或消息驱动bean)或者选择在bean的实现类中使用Annotation。你可以使用无状态,状态,消息驱动或者实体去注释一个bean类。例如,如果你定义一个无状态EJB作为HelloWorld,你可以如下定义EJB:
@Remote
@Stateless public class HelloWorldBean {
public String sayHello(String s)
{ System.out.println("Hello: "+s; }
}
The interfaces for EJBs either remote or local do not have to implement EJBObject or EJBLocalObject. You have to either supply the business interface for your EJB and implement that interface in your bean class or have it generated during the deployment. Interfaces are optional for Entity beans however required for SessionBean and MessageDrivenDriven. If you do not implement an interface for your session bean, a bean interface will be generated for you. The type of generated interface either local or remote is dependent on the annotation you used in the bean class. If you look at the above code example, it is very clear that @Remote is used to generate a remote interface for the HelloWorld bean. If needed, you may have both remote and local interfaces for your EJB.
EJB的接口无论远程的还是本地的都不必再实现EJBObject和EJBLocalObject。你要么为EJB提供业务接口并且实现bean类中的接口,要么需要在部署的时候生成这些接口。虽然会话bean和消息驱动bean的接口是必须的,但是实体bean的接口是可选的。如果你没有为你的会话bean实现一个接口,那么它会自动为你生成一个。所生成的接口是本地的还是远程的取决于你在bean类中的Annotations。如果你仔细看看上面的代码范例,@Remote很明显是用来为你的HelloWorld生成一个远程接口。如果需要,你可以在你的EJB中同时生成远程和本地接口。
From the above example, it is very clear that the developer do not have to a lot of mundane tasks such as defining interfaces and implementing callback methods.
在上面的例子中,很明显开发人员不必再做那些如定义接口和实现回滚方法等这些普通的工作。
The name of the generated interface is derived from the name of the bean implementation class. Generated interfaces are well and good for developers. However, I do not see any benefit of generating interfaces as most IDE like Oracle JDeveloper generates these on fly.
生成接口的名字来源于bean实现类的名字。生成接口对开发人员来说非常有用。但是我并没有看到任何如Oracle 的JDeveloper的这些IDE立即实现这种生成接口功能。
This is not clear from the draft what is client side requirement for EJB lookup and it is not clear, how do we get hold of these interfaces those are required to invoke this EJB? I will recommend against using a generated interface for few reasons:
规范中没有明确EJB查找时客户端的需求是什么,也没有明确我们如何保持这些EJB需要调用的接口。基于以下几个情况下的原因我将不推荐使用生成接口:
The name of generated interface will be derived from the bean name
生成接口的名字来源于bean的名字
You may not be willing to expose some methods in the EJB in the interface and the generated interface may expose all methods by default.
如果你不愿意在EJB中暴露出一些方法而生成接口将默认暴露出所有的方法。
You need the interface at the client side to invoke the EJB.
你需要在客户端使用接口来调用EJB.
Removing need for Callback methods去掉回滚方法的需求。
EJB 2.1 and prior releases required implementation of several lifecycle methods such as ejbPassivate, ejbActivate, ejbLoad, ejbStore, etc. for every EJB even if you do not need those. For example, ejbPassivate is not required for a stateless session bean still you require to implement that method in your bean class. As EJB 3.0 now resembles regular Java classes implementation of these lifecycle methods have been made optional. If you implement any callback method in the EJB then container will invoke that method.
EJB2.1和更早版本需要实现很多即使对于每个EJB你不需要的一些生命周期的方法,如ejbPassivate, ejbActivate, ejbLoad, ejbStore等等。例如,在无状态会话bean中不需要ejbPassivate但是你还是得实现它的方法。现在EJB3.0中类似的常用Java类实现这些生命周期的方法都变成为可选择的。如果你在EJB中实现任何回滚容器都会调用这些方法。
The only exception is the ejbRemove method in Stateful Session bean where you can use Remove annotation to annotate a Stateful session bean business method. If you use of this annotation it will hint the container to remove the Stateful session bean instance after the completion (normal or abnormal) of the annotated method. For example, you can specify the following to remove a Stateful Session Bean instance after checkOut method is executed.
唯一的异常是在你可以使用Remove的annotations时一个状态会话bean的业务方法的ejbRemove方法是状态会话bean。如果你使用这个annotations它将在完成annotations方法后(无论正常或非正常)提示容器移除状态会话bean实例。例如,你可以指定以下的方式去在checkOut方法执行后移除一个状态会话bean实例。
@Stateful public class Cart {
...
...
@Remove public void checkOut() {
...
}
}
Annotations vs. deployment descriptors
Annotations与部署描述的比较
As we discussed earlier deployment descriptors will no longer be required for EJBs and annotations will be used instead. The default values for each attribute in the deployment descriptor will be chosen and developers do not have to specify these attributes unless they want a value other than the default value. These can be specified using annotations in the bean class itself. The EJB 3.0 specification is defining a set of metadata annotations for use by developers such as bean type, type of interfaces, resource references, transaction attributes, security, etc. For example, if we want to resource reference for a particular EJB then we will define as follows:
在前面我们讨论到EJB中不再需要部署描述而由annotations代替。每个部署描述的属性都将被选择一个默认值,而开发人员在直到他们想改变这些属性的默认值之前不必为这些属性指定值。这些也能用来为bean的类自身指定使用的annotations。EJB3.0规范为开发人员使用bean类型,接口类型,资源引用,事务属性,安全等等定义了一组metadata annotations。例如,如果我们可以如下为一个特殊的EJB定义使用资源引用:
@Resource(name="jdbc/OracleDS", resourceType="javax.sql.DataSource")
J2EE vendors such as Oracle, BEA, IBM will add annotations for attributes in their vendor specific deployment descriptors and developers will use these to avoid using deployment descriptors. This looks very attractive for developers as the nasty XML descriptors they hated most gets out of their way but this introduces few problems and we need to be careful before embracing annotations.
J2EE的提供商如Oracle, BEA, IBM将增加属性annotations在他们指定的部署描述中,开发人员将可以使用这些annotations去避免使用部署描述。这看起来对开发人员十分具有吸引力,特别对XML描述是已经感到厌恶的开发人员,他们早就恨透并想脱离老的那种描述方式,但依然有一些问题使得我们在正式使用annotations时需要谨慎对待。
This defeats the goal of portability of applications because if an EJB uses a vendor specific deployment descriptor this cannot be just changed without having to recompiling/repackaging the EJBs.
它违背了我们轻便应用程序的目标,因为如果一个EJB如果使用一个提供商指定的部署描述,在重新编译或打包EJB的时候它必须多次改变。
The deployment descriptors provided a holistic view of EJB modules to the assembler/deployer (ejb-jar) without having to look at individual the EJBs and they tweaked these as per the deployment requirement and if descriptors are not available or not generated until the end of deployment this could be a nightmare for them.
部署描述对EJB模板提供了全局观点使得组装和部署的时候不必考虑单独的EJB,他们将每个部署需求拧在一起,并且在部署完成之前描述是无效或者不可自动生成的。这对部署员来说是个可怕的事情。
Deployment descriptors were used by the tools to identify the EJBs in an EJB module and were very useful when you try to migrate from one container to another.
EJB 3.0 spec also proposes a way to override the annotations in the deployment descriptors. However details of overriding annotations is missing in the specification.
部署描述在EJB模板中被相关工具用来定义EJBs,当你试图整合一个和另一个容器的时候非常有用。EJB3.0规格同样主张在部署描述中使用重载annotations的方式。可是在规范里并没有提到重载annotations的细节。
There is no doubt that getting rid of deployment descriptors will make the life easier for new developers but this may become a management nightmare if not used carefully.
无疑摆脱部署描述将使得新的开发者开发更加容易,但是如果使用不当这也将造成管理上的可怕问题。
Simplifying Container Managed Persistence简化持久化容器管理
CMP entity bean is getting a major overhaul in EJB 3.0 to make it compelling for developers. Persistence frameworks like OracleAS TopLink, open source Hibernate have become darling of developing persistence framework for J2EE applications that has disliked Entity beans for its complexity and heavyweight in nature. EJB 3.0 is adopting a lightweight persistence model like TopLink and Hibernate to simplify the container managed persistence and this sounds compelling for developers. Let us do a quick look on the plans for entity beans and we will discuss about the details of the persistence improvement in another article.
CMP实体bean将成为EJB3.0使得开发人员强制使用的一个主要的检查方式。持久化框架象如OracleAS TopLink, 开源的Hibernate已经成为不像实体bean本质上的复杂和重量级的开发J2EE持久化框架应用的被大家喜爱的方式。 EJB3.0采纳了如TopLink和Hibernate轻量级的持久化模式来简化容器持久化管理,这些听起来更让开发人员们欣喜。让我们简单的浏览一下实体bean的计划,我们将在另外的文章中讨论持久化改进的细节。
Entity beans are being reincarnated as POJOs and there will be no component interfaces required for entity beans. Entity beans will now look as pure objects as this will also support inheritance and polymorphism.
实体bean作为POJOs已经改头换面,实体bean将不在需要组件接口。实体bean现在看起来是支持继承和多态的纯粹的对象。
Following is the source code for an entity 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;
}
....
}
If you look at the code, you will find that the bean class is a concrete class and not an abstract class the current entity bean.
如果你仔细看这些代码,你可以发现在现在的实体bean中bean类是一个具体的类而不再是一个抽象类。
There are several improvements are being made for the query capabilities in EJB QL and support of SQL queries in the entity beans. A new EntityManager API similar to Hibernate and a simplified version of TopLink’ Session API is being proposed to manipulation of entity beans i.e. creation, removal, finding of entity beans.
EJB QL和实体bean的SQL查询做了多项改进。类似于Hibernate的新的实体管理API和简化版的TopLink的会话API被建议用来处理实体bean的操作,也就是实体bean的创建,释放,查找。
We will closely examine the details of the proposed CMP entity beans in a followup article.
我们将在深入的文章中进一步对建议CMP实体bean的细节做更多的验证。
Simplifying Client View for EJBs简化EJB客户端
Using EJBs i.e. to lookup and invoke is very complex even if EJB is collocated in the application. J2EE 1.4 and EJB 3.0 spec is working on to simplify the client’s view of EJBs.
即使应用中EJB是序列化的,使用EJB也就是寻找和调用也是非常复杂的。J2EE 1.4 和 EJB 3.0规范致力于简化EJB客户端。
If you want to use an EJB presently you have to define the ejb-ref or ejb-local-ref in the deployment descriptor, lookup the EJB and then invoke. If we want to invoke our HelloWorld EJB, following is the simplest way you can invoke an EJB with the current implementation.
如果目前你希望使用EJB你必须在部署描述中定义EJB引用或者EJB本地引用,寻找到EJB然后调用。如果我们希望调用HelloWorld 的EJB,你可以按照下面的简单方法调用EJB使用已存在的实现。
First define the EJB references in the deployment descriptor as follows:
如下在部署描述中找到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>
Then lookup the EJB as follows. You have to explicitly handle exceptions for EJB lookup and creation of a bean instance.
然后按照如下方法寻找EJB.你需要明确处理EJB查找和建立一个bean实例时的异常。
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());
}
As an alternative to environment variables, EJB 3.0 proposes a way to use setter injection to lookup and invoke EJBs.
如一个环境变量的变化一样,EJB3.0建议使用安放injection的方法查找和调用EJB.
Following is way our HelloWorldEJB can be looked up in another EJB by using setter injection.
下面我们使用安放injection的方法在另一个EJB查找HelloWorldEJB。
@Inject private void setSessionContext(SessionContext ctx)
{
this.ctx = ctx
}
...
myHello = (HelloWorld)ctx.lookup("java:comp/env/ejb/HelloWorldEJB");
If you look at the code above carefully the setSessionContext method is annotated with @Inject to specify that dependency injection be used for this method. The injected methods will be invoked by the container to set the EJBContext before any business method be called on that EJB.
如果你仔细查看上面的代码,它依赖的injection使用@Injectset来的指定对SessionContext方法的annotations。injection 方法将可以在业务方法被EJB调用前被容器调用来设定EJBContext。
Another direct example to inject the HelloWorld session bean would be to simply have @EJB public HelloWorld myHello and this would cause myHello to be injected with an instance of the HelloWorld bean.
另一个injected 的HelloWorld会话bean的直接的范例可以简化为使用
@EJB public HelloWorld myHello,这将使得myHello被HelloWorld bean的实例injected 。
You can use dependency injection to lookup any type of environment and resource references such as DataSource, JMS, Mail, Web Service, etc.
你可以使用依赖的injection来查询任何类型的环境和资源参考如DataSource, JMS, Mail, Web Service等等。
Testability Usability Outside Container容器外部测试可行性
A major concern for the current EJB developers is not only development of EJBs is complex but also testing is a nightmare. An EJB container is required is to develop and test the EJBs and the developers have to be familiar with the final deployment platform to perform testing. This may not be a major issue for many enterprise developers but is an issue for ISVs who work on supporting multiple vendors and they have to maintain multiple environments to do the testing of their EJBs. The EJB 3.0 spec promises to provide the ability to test outside the container but this is currently missing in the draft specification.
一个现在EJB开发者所关注的不仅仅是EJB开发的复杂,也包括了测试的可怕之处。开发和测试EJB必须需要一个EJB容器并且开发人员必须熟悉最终部署平台才可以执行测试。这对于许多只在一个主要平台开发的企业开发人员来说不是主要问题,但是对于支持多个开发商平台并且要在维护的多个环境中测试EJB的ISV们来说是个大问题。EJB3.0规范承诺将提供在容器外测试的功能,但是这点在这次的规范中遗漏掉了。
Conclusion结论
Although there are a lot of missing information about packaging, assembly and gory details of APIs, the proposals made in EJB 3.0 drafts looks very promising for enterprise java developers. These will certainly help remove the complexities from developers view by passing those to the container vendors. It is to be seen how the container vendors implement these and make EJB 3.0 a compelling option to develop enterprise applications.
虽然还有很多关于打包,装配和重要的API细节没有在这个规范中提及,但是诸多的建议使得EJB3.0规范让企业级Java开发人员看起来是恨有前途的。通过这些无疑是从开发人员到服务供应商都将帮助减少开发的复杂性。下面就要看服务提供商们怎么实现,并使得EJB3.0成为企业级应用一个引人瞩目的选择。
Author Bio 作者自述
Debu Panda is a principal product manager of Oracle Application Server development team, where he focuses his efforts on the EJB container and Transaction Manager. He has more than 13 years of experience in the IT industry and has published articles in several magazines and has presented at many technology conferences.
Debu Panda是Oracle应用服务开发小组的主要管理者,他的在EJB容器和事务管理上取得过很多成就。他已经有13年的IT产业的经验并在多家杂志和技术出版社刊登过很多著作。
翻译问题:
由于部分英文名词未敢枉自翻译,所以留英文原词在文中
Cleaning up the Dirty Laundry 整理缺陷
low carb
Atkins diet
metadata annotations 元数据描述
Simplifying Client View for EJBs 简化EJB客户端
dependency injection 依赖型injection
setter injection 安放injection
ISV Independent software vendor 独立软件供应商