EJB的七年之痒

来源:百度文库 编辑:神马文学网 时间:2024/04/28 03:06:44
EJB的七年之痒

曾几何时,EJB被人们当作J2EE的核心而顶礼膜拜。可惜,过去七年的经验退去了EJB的光环。我现在更多的把EJB当作一种过渡性技术:它普及了很多有价值的思想;但对于大多数新的应用来说。它并不是最佳的选择。

 

EJB的原意是简化企业应用的开发,让应用开发人员将注意力集中于他们的问题领域和编写业务逻辑。而不是去关注系统的问题。同时,EJB规范也承诺EJB(以及基于EJB的应用)在不同AppServer之间的可移植性。那么这些期望达到了吗?

 

一个过时的组件模型

 

19983月,当EJB第一次出现时,在企业软件领域根本没有标准。微软事务服务器(MTS)可能是最接近一个企业组件框架的东西,但它是厂商专有的,而且依赖于微软C++和其他语言并不优雅的扩展,并且紧密绑定在COM/DCOM上。

 

在这样的环境下,EJB看起来即简单又开放。然而,随后几年的技术发展,使得EJB不再象当初那样具有独到的优势。

 

Java语言的规范

 

EJB1.0规范是在Java1.2API进行重大改进之前6个月发布的。J2SE1.3又对Java进行了更为重大的改进。例如动态代理(dynamic proxy),它使得任何接口可以被一个运行时生成的代理所实现。有了这样的能力,EJB所采用的那种不完全匹配组件接口的实现方式看起来越发的笨拙,要求一个专门的部署阶段也同样值得怀疑;实际上,很多EJB容器厂商很快利用动态代理的先进技术取消了代码生成和编译的步骤。而这正是EJB部署过程中的重要一环。看起来,大多数厂商都同意:session bean不再需要代码生成的支持,只有entity bean才有必要。

 

.NET的挑战

 

EJB最初的灵感部分来自于MTS。不过EJB的吸引力比MTS可要大得多。在EJB的大部分时间里,微软缺乏一个可信任的企业架构,COM/DCOMMTS都无法令人信服。EJB在这个领域基本上无人竞争。

 

2002年初,随着雄心勃勃的微软.NET企业平台的发布,情况发生了改变。.NETJ2EE的影响颇深。微软从J2EE专家这里汲取了大量知识。同时,.NET又与J2EE有一些显著的差异,特别值得一提的是与EJB的差异。

 

.NET模糊了web容器和ejb容器之间的区别,而这两种容器恰好是经典”j2EE架构的根本。任何一种.NET语言中的对象都可以通过继承ServicedComponent来使用企业级服务,这里没有独立于受控环境的特殊容器。这意味着任何对象都可以享受企业级服务,而不需要特殊的部署阶段,也无须在开发时承担那么沉重的包袱。(我并不欣赏强制继承ServicedComponent”的做法,但那也好过实现一个EJB

部署这样一个享受企业级服务的组件比部署EJB简单多了。因为.NET也炮击了j2EE中的很多外部部署描述文件。比如说,对于用于声明性事务管理的元数据,.NET不是将它们放在独立的XML部署描述文件(例如ejb-jar.xml)中,而是以元数据属性的形式存放在实际的组件源程序中。(代码重构不会破坏源码级元数据,这正是外部部署描述文件的一个重大缺陷。

 

j2EE社区,关于J2EE.NET的争吵从来未断,而且全部都是毫无价值的老调重弹。幸运的是,J2EE社区中的一些重要的推动者们显示出了一种开明的态度,他们愿意采用一些.NET所开创的有价值的特性,例如:

 

Java1.5Java添加源码级元数据,以及C#风格的autoboxing功能。

JBoss4采用了.NET风格的元数据来驱动企业服务。

Spring和其他AOP框架(除了JBoss AOP之外)也使用了源码级元数据。

EJB3.0采用源码级元数据来描述目前保存在XML EJB部署描述文件中的信息。

 

Web Service

 

EJB1.01.1的年代,除了Java自己的RMI/RMP之外,重要的分布式对象技术就只有CORBACOM/DCOM(这两种技术很复杂,都没有被业界大量采用)。相比之下,EJB更加简单,概念更加一致。因此它成功地在很多系统中引入了分布式对象。

如今,情况已经大不相同了,基于XMLweb service提供了比过去大得多的开放性,这是真正的互操作,不仅仅是在微软技术和基于Java的解决方案之间,还可以在多种语言和系统之间实现互操作。同时,越来越多的人认识到,分布式对象的使用仅仅在少数应用中才是适合的。因此,快速增长的领域是在异构平台之间的互操作性,而不是J2EE应用服务器之间的远程调用。

 

敏捷方法学的兴起

 

自从EJB1998年诞生之后,开发过程和最佳实践的思想发生了重大变化。可能最重要的事件就是敏捷方法学的兴起,例如极限编程(eXtreme Programing)

尤其值得一提的是,测试先行的开发(test first development),或者至少是严格的单元测试,其价值在很多项目中得到了证实。而EJB使得有效的unit test非常困难,因为EJB严重依赖容器的服务。因此这就意味着EJB使得敏捷开发过程难以被应用。

 

从未出现的组件市场

 

我们对EJB的失望还在于它没能成功地创造一个第三方组件市场,而这是其承诺的主要愿景之一(还记得EJB规范所设想的,将多个厂商提供的EJB”组装起来构成应用程序得情况吗?)

这个组件市场并没有出现,它是否真的会出现也很值得怀疑。之所以这样,一部分是因为EJB的模型(可移植性有缺陷,部署也过于复杂),然而更重要的是企业组件太过复杂,有太多的依赖关系需要包装。

 

方兴未艾的新范式AOP

 

最后不得不提的是,一种新的编程模型正在浮出水面,那是一种更为通用的解决方案。仅仅其中的一部分就能够提供EJB大多数有价值的能力,那就是面向切面编程(Aspect Oriented Programming).J2EE中,我们主要用到AOP的拦截(interception)能力。它为我们提供了在任何对象的方法调用前/后加入自定义行为的能力。这使得我们可以处理企业应用中的横切(crosscutting)关注点(同时作用于多个对象的关注点)。例如我们使用AOP可以把与事务管理相关的重复劳动放进一个框架内;另外一个很适合使用AOP的场合则是自定义安全检查。

 

EJB为我们提供了什么

 

有经验的系统架构师倾向于只使用EJB的一小部分。毫无争议SLSB(stateless session bean)EJB中最有用的,然后是message-driven bean(用于异步操作)Entity bean则可能是EJB规范中最虚弱的部分。它的性能相当差,并且没有解决好ORM最重要的问题。

 

为什么SLSB如此流行?因为它是简单的组件,并且对一些企业系统常见的问题提供了一个相当好的解决方案。下面,让我们逐一审视SLSB提供的主要服务:

 

声明式事务管理

SLSB最有价值的服务可能就是容器管理的事务CMT了。尽管最终通过JTS/JTA协调事务的是J2EE服务器而不是EJB容器,但SLSB让我们可以使用声明性,而非编程性的事务管理。(当然如果想要回滚事务,我要需要使用EJB API,但是在理想的状态下我们不必为事务管理写一行代码)

尽管EJB CMT对于大多数应用来说很有价值,但要处理一些复杂的事务管理问题就显得力不从心了。(比如说,有时一个业务操作需要多个事务,如果每次事务都通过一个EJB入口点调用一个EJB方法,这就比通过编程方式界定事务更复杂了。乐观的锁定策略也会成为一个问题。如果我们使用声明性事务来驱动一种持久技术执行乐观事务,乐观并发异常将在容器提交事务之后才出现,而此时应用代码已经将控制权交给了EJB容器,很难重新控制程序的运转。EJB没有为这类更复杂的场景提供良好的支持。如果使用Bean管理事务(BMT)EJB,则需要从JNDI得到JTA User Transation的对象,然后直接使用JTA API。在同一个EJB中混合BMTCMT也是不可能的。

 

因此,可以同时适应高端和低端的轻量级,更少侵入性的事务基础架构才是真正的价值所在。例如Spring框架提供的基于AOP的声明性事务管理可以通过配置,在支持多个数据库的JTA或者JDBC或者其他的特定于资源的事务管理API(例如JDO事务API)之间切换,而不需要对业务代码做任何修改。

而且,EJB CMT还可以做得更加灵活。只有当业务方法抛出一个unchecked异常时,EJB容器才会回滚事务。这样的处理方式不是我们通常希望的,如果能够指定哪些unchecked异常可以直接触发事务回滚就更好了(这样的自动回滚将不被视为程序错误)Spring的声明性事务管理通过回滚规则提供了这样的能力(不需要调用一个特定于框架的setRollbackOnly()方法)

 

远程调用

远程调用也是EJB(尤其是SLSB)证实自身价值的领域。EJB2.0, SLSB只能提供RMI远程调用;EJB2.1增加了Web Service远程调用。

然而,很多人认为EJB规范混淆了远程和组件模型。很多时候,我们根本不需要远程调用。EJB极大地简化了远程调用,也使它成为一种危险的诱惑---诱惑人们采用一种并不实用,而且可能非常昂贵的体系结构(昂贵在复杂性,工作量和性能上)

Web应用中,将web组件和业务组件放在同一个JVM中几乎总是一个更好的主意。在这类应用中使用带远程接口的EJB无法增加任何价值,通常对于设计还是有害的。