当前页面位置: » 丰搜网 » 文档中心 » 详细内容
pojo应用框架:spring与ejb3.0的比较
pojo应用框架:spring与ejb3.0的比较作者:michael juntao yuan06/29/2005翻译:loryliu版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
英文原文地址:
http://www.on
java.com/pub/a/on
java/2005/06/29/
spring-
ejb3.
html中文地址:
http://www.matrix.org.cn/resource/article/43/43718_
spring_
ejb.
html关键词:
spring ejb艾伯特.爱因斯坦曾经说过:“一切都应该尽可能地简单,但是不能更简单。”确实如此,简化一门理论的基本假设,使我们可以专注于真正关键的地方,这正是一直以来对科学真理的追求。企业软件开发同样如此。
提供一个将复杂的事物(例如,事务、
安全或持久性)对开发者进行隐藏的应用
框架是简化企业软件开发的关键。一个设计良好的
框架可以提高代码重用率、开发者的生产力及软件的质量。然而,现有
j2ee1.4的
ejb2.1
框架被普遍认为设计差,且过于复杂。不满于
ejb2.1的
框架结构,
java开发者尝试了各种各样的中间件服务传递方法。最引人注目的是,以下两个
框架引起了开发者极大兴趣并得到了大量正面的反馈。他们以未来企业
java应用所选
框架的姿态展现。
spring框架虽然很流行但并不是一个标准的
开源框架。它主要由interface21 inc开发和控制。
spring框架结构是基于依赖注入(dependency injection (di))的设计
模式。它可以独立或在现有的
应用服务器上运行,而且大量地使用了
xml配置文件
ejb3.0是由
java community process (jcp)制订的标准
框架,为所有主要的
j2ee厂商支持。
jboss已经提供了试用版
ejb3.0标准的
开源或商业性质实现。
ejb3.0充分利用了
java的注释
这两个
框架结构都有一个共同核心设计理念:将中间件服务传递给耦合松散的pojos (plain old
java objects, 简单洁净
java对象)。 这样的
框架利用截取执行上下文或在运行时将服务对象注入pojo来把应用服务“缠绕”到pojo。pojo本身并不关心这种“缠绕”,对这种
框架结构也没有什么依赖。因此,开发者可专注于业务逻辑和脱离
框架的pojo单元
测试。除此之外, 由于pojo并不须要继承
框架的类或实现其接口,开发者能够极其灵活地搭建继承结构和建造应用。
然而,在拥有同一理念的同时,两个
框架结构使用不同的方式来传递pojo服务。许多书籍或文章都将
spring 或
ejb3.0和
ejb2.1做了比较,但是对
spring 和
ejb3.0的比较并没有仔细研究过。在本文中,我将对srping和
ejb3.0
框架背后的关键不同处进行考察,并讨论其优缺点。本文的观点也适用于其它更少为人知的
框架,因为他们都是对“耦合松散的pojo”的设计。希望这篇文章可以帮助你选择适合你需求的最好
框架。
厂商无关性开发者选择
java平台其中最引人注目的理由之一:厂商无关性。
ejb3.0正是一套设计为厂商无关的开放性标准。
ejb3.0标准为所有企业
java社团里
开源或商业性质厂商所开发和支持。它将开发者与
应用服务器实现完全隔离。例如,
jboss的
ejb3.0实现基于
hibernate,
oracle的基于toplink,但是开发者并不须要学习
hibernate- 或toplink的具体api来使应用可在
jboss或
oracle上运行。厂商无关性使
ejb3.0与现今其它pojo中间件
框架区别开来。
但是,正如许多
ejb3.0评论家迅速所指出的,在本文撰写时
ejb3.0标准还没有到达一个最终版本。大概还有一到两年的时间
ejb3.0才能广泛地为所有主要
j2ee厂商所支持。即使你的
应用服务器本身不支持
ejb3.0,你仍然可以通过下载安装”内嵌的”
ejb3.0产品来运行
ejb3.0的应用。例如,
jboss的内嵌
ejb3.0是
开源产品且可以在任何
j2se5.0兼容的环境运行(例如, 在任何
java服务器上),此产品正处于软件
测试阶段。其它厂商不久也将发布自己的内嵌
ejb3.0产品,特别是针对标准中关于数据持久性的部分。
另一方面,
spring一直以来都是非标准的技术,在未来可预知的一段时间内这种情况将持续下去。虽然你可以在任何
应用服务器上使用
spring框架,
spring应用会被锁入在
spring本身和你选择整合进
spring的具体服务中。
spring框架是一个
开源项目,但同时它有一个
xml格式的配置文件和编程接口。当然任何一个非标准的产品都会有这种“锁入”(lock-in)的情况,并不是
spring特有的。但
spring应用的长期生存能力仍然还得托
spring这个项目的福(或者是interface21公司,它雇佣了大部分
spring核心开发人员)。除此之外,假如你用到任何一个具体的
spring服务,例如,
spring事务管理器或则
spring mvc,你也会被锁入到这些api里。
spring的应用对终端用户是不可知的。例如,对数据持久服务,
spring框架兼容不同的dao和jdbc的模版帮助类,如
hibernate, ibatis, 和 jdo。所以假如你需要为
spring应用切换在数据持久化服务(例如从jbdc到
hibernate),你需要修改你的代码以适合新的模版帮助类。
服务整合从一个很高的角度上看,
spring框架处于
应用服务器和服务库的上方。服务整合的代码(如,数据访问模板和帮助类)属于
框架,并暴露于应用开发者。相反,
ejb3.0
框架与
应用服务器高度整合,服务整合代码也包装在一个标准接口后面。
因此,实现
ejb3.0的厂商可以大大地优化整体性能和提升开发者的体验。例如,在
jboss ejb3.0的实现中,当你在用entitymanager持久化一个entity bean时,后台的
hibernate会话事务已经自动地帮定到调用方法的jta 的事务上,在jta 事务提交的同时
hibernate会话事务也提交了。你甚至可以使用一个简单的 @persistencecontext 注释(稍候例子演示)将entitymanager和它后台的
hibernate事务绑定到一个stateful session bean的应用事务中。在一个会话中应用事务横跨多个
线程,这在事务性网页应用很有用,例如,多页面的购物车。
由于高度整合的
ejb3.0的
框架,使简单、集成的编程接口成为可能。
oracle ejb3.0
框架和其后台的toplink持久化服务也同样程度地整合。
另一个
ejb3.0整合服务的绝好例子就是集群支持。假如你在一个
服务器集群上部署了一个
ejb3.0的应用,所有容错(fail-over)、负载均衡、分布式缓冲和状态复制都已经自动为应用所获得可用。后台的集群支持被隐藏在
ejb3.0的
框架后面,对
ejb3.0开发者来说这些都是完全透明不可见的。
在
spring里,很难优化
框架和服务之间的通讯。例如,为了使用
spring里的声明事务服务来管理
hibernate事务,你必须显示地在
xml文件中配置
spring transactionmanager和
hibernate sessionfactory对象。
spring必须电显示地管理横跨多个http请求的事务。除此之外,没有别的方法均衡
spring应用里的集群。
服务组合的弹性由于
spring的服务整合代码作为编程接口的一部份暴露在外,应用开发者有按自己需求装配服务的弹性。这个特点使你能够组合自己的轻量级
应用服务器。
spring的一个普遍用法就是将
tomcat和
hibernate组合在一起支持
数据库驱动的
web应用。在这种情况,
spring本身提供事务服务,hibernat提供持久化服务——这种设置创建了一个袖珍型的
应用服务器。
ejb3.0
应用服务器典型地不提供这种根据需求任你挑捡服务的弹性空间。大多数时间,你得到的只是一系列包装好的特性,其中一些你可能根本就不需要。但是如果
应用服务器像
jboss一样提供一个模块性的内部设计,那么你可以只取其中一部分,而把不必要的部分剥去。在任何情况,去自定义一个功能强大的
应用服务器是没有什么价值的。
当然,假如应用已经超过单个点,那么你应该加入常用
服务器上的服务,例如,资源池(resource pooling),消息队列(message queuing)和集群(clustering)。就总体的资源消耗而言,
spring解决方法和其他
ejb3.0解决方法一样是重量级的。
在
spring框架里,具有弹性的服务装配使得将虚拟对象而不是真正的业务对象绑定到应用中做脱离容器的单元
测试更简单。在
ejb3.0应用中,大多数组件都是简单pojo,他们可以很容易地在容器外被
测试。但是对于与容器服务相关的对象(例如持久化实实体管理器entitymanager)建议用容器内
测试。因为这样会比虚拟对象
测试方法更简单,强壮及准确。
xml vs.注解从应用开发者的观点上来看,
spring的编程开发接口主要基于
xml配置文件而
ejb3.0广泛地应用
java注解。
xml可以表达复杂的关系,但是它也冗长且不够健壮;注解简单明了,但是很难在注解里表达复杂或继承性的关系。
spring选择
xml或
ejb3.0选择注解都是有他们两者
框架后的体系结构决定的。因为注解只能容纳很少的配置信息,只有整合前的
框架(重头戏都在
框架里)才可以把广泛地使用注解作为配置选择。正如我们所讨论过的,
ejb3.0刚好符合这个要求,而
spring作为一个普通的di
框架并不符合。
当然,
ejb3.0和
spring都相互取长补短,在某种程度上他们都支持
xml和注解。例如,在
ejb3.0中,
xml配置文件作为一个可选的重载机制来改变注解的默认行为。注解也可以配置一些
spring服务。
通过例子是学习
xml和注解方式之间差异的最好方法。在下面几个环节里,让我们来看看
spring和
ejb3.0是怎样提供关键服务给应用的。
声明性服务spring和
ejb3.0都将运行时服务(例如,事务、
安全、日志和配置服务)绑定到应用。因为这些服务于应用的业务逻辑是没有直接联系,他们只是由应用本身管理。换句话说,这些服务在运行时由容器透明地应用到应用中。开发者或是管理者配置容器,准确地告诉它什么时候怎样应用这些服务。
ejb3.0运用
java注解来配置声明性服务,而sring使用
xml配置文件。在大多数情况下,
ejb3.0注解方式对于这种服务更简单明了。这里有一个在
ejb3.0中将事务服务运用到pojo的例子。
public class foo {
@transactionattribute(transactionattributetype.required)
public bar () {
// do something ...
}
}你也可以为一个代码段声明多个属性,应用多个服务。这是一个在
ejb3.0里同时应用事务和
安全服务到pojo的例子。
@securitydomain("other")
public class foo {
@rolesallowed({"managers"})
@transactionattribute(transactionattributetype.required)
public bar () {
// do something ...
}
}
使用
xml说明代码属性和配置声明性服务会导致冗长和不稳定的配置文件。下面是一个在
spring应用中的
xml片段,其应用一个非常简单的
hibernate事务到方法foo.bar()中。
<!-- setup the transaction interceptor -->
<bean id="foo"
class="org.springframework.transaction
.interceptor.transactionproxyfactorybean">
<property name="target">
<bean class="foo"/>
</property>
<property name="transactionmanager">
<ref bean="transactionmanager"/>
</property>
<property name="transactionattributesource">
<ref bean="attributesource"/>
</property>
</bean>
<!-- setup the transaction manager for hibernate -->
<bean id="transactionmanager"
class="org.springframework.orm
.hibernate.hibernatetransactionmanager">
<property name="sessionfactory">
<!-- you need to setup the sessionfactory bean in
yet another xml element -- omitted here -->
<ref bean="sessionfactory"/>
</property>
</bean>
<!-- specify which methods to apply transaction -->
<bean id="transactionattributesource"
class="org.springframework.transaction
.interceptor.namematchtransactionattributesource">
<property name="properties">
<props>
<prop key="bar">
</props>
</property>
</bean>
xml的复杂度会以几何级数增长,如果你向同一个pojo添加更多的拦截器(interceptors)(例如
安全拦截器)。意识到只有
xml配置文件的局限,
spring使用apache commons 元数据在
java源码中来说明事务属性。最新版本的
spring1.2也支持jdk-1.5风格注解。要使用事务元数据,你须要将上面的transactionattributesourc bean变成一个attributestransactionattributesource实例。并为元数据拦截器添加额外邦定。
class="org.springframework.aop.framework.autoproxy
.defaultadvisorautoproxycreator"/>
<bean id="transactionattributesource"
class="org.springframework.transaction.interceptor
.attributestransactionattributesource"
autowire="constructor"/>
<bean id="transactioninterceptor"
class="org.springframework.transaction.interceptor
.transactioninterceptor"
autowire="bytype"/>
<bean id="transactionadvisor"
class="org.springframework.transaction.interceptor
.transactionattributesourceadvisor"
autowire="constructor"/>
<bean id="attributes"
class="org.springframework.metadata.commons
.commonsattributes"/>
当你有很多事务性方法时,
spring元数据可以简化transactionattributesource。但是这并没有解决
xml配置文件的根本问题。冗长而又繁琐的事务拦截器, transactionmanager,和transactionattributesource仍然需要。
依赖注入(dependency injection, di)中间件容器的一个关键好处之一就是它可以让开发者建造一个关系耦合松散的应用。服务端客户只需要知道服务的接口。容器依据具体的实现实例化服务对象,使他们为客户端所用。在不改变接口和客户端代码的情况下,这使得容器可以在多种服务实现之间切换。
依赖注入的
模式是实现耦合松散应用的最好方法之一。它更易用,比其他方法也明了多了,比如通过jndi依赖性查询或容器回调。使用di,
框架就像一个对象工厂,它创建服务对象然后按照运行时配置将这些服务对象注入到应用的pojo里。站在应用开发者的角度,客户端pojo在被使用时可自动获得正确的服务对象。
spring和
ejb3.0都提供广泛的di
模式支持。但是他们之间仍存在很大的不同之处。
spring支持一般意义上且复杂的di api,其基于
xml配置文件。
ejb3.0支持大多数普通服务对象(如
ejb及context对象)的注入和任何简单注解的jdni。
ejb63.0注解非常简单易用。@resource 标记表示注入大多数普通服务对象和jdni对象。以下例子展示了怎样把服务的jdni的默认datasource 对象注入到pojo的一个属性变量中。defaultds是datasource.的jdni名字。mydb变量在第一次被使用时被赋上了正确的值。
public class foodao {
@resource (name="defaultds")
datasource mydb;
// use mydb to get jdbc connection to the database
}除了直接属性变量注入,
ejb3.0的@resource注解也可以用来在setter方法里面注入对象。例如,下面的例子就是注入session context对象。应用从不会显示地调用setter方法,其在其他方法被调用前由容器来触发。
@resource
public void setsessioncontext (sessioncontext ctx) {
sessionctx = ctx;
}
针对更复杂的服务对象,定义了专用的注入注解。例如,@
ejb注释用来注入
ejb的stub,@persistencecontext注解用来注入处理
ejb3.0实体bean访问
数据库的entitymanager对象。下面是一个怎样将entitymanager对象注入有状态的 session bean的例子。@persistencecontext的type属性具体说明了被注入的entitymanager有一个扩展的事务transaction context。transaction context并不会同jta transaction manager一起自动提交。因此它可以用在在一个会话横跨多个
线程的应用事务中。
@stateful
public class foobean implements foo, serializable {
@persistencecontext(
type=persistencecontexttype.extended
)
protected entitymanager em;
public foo getfoo (integer id) {
return (foo) em.find(foo.class, id);
}
}
ejb3.0标准通过注解可以被注入的
服务器资源。但是它并支持将用户定义的应用pojo之间的相互注入。
在
spring中,首先你必须为pojo中的服务对象定义一个setter方法。下面的例子说明pojo需要一个
hibernate session 的引用
public class foodao {
hibernatetemplate hibernatetemplate;
public void sethibernatetemplate (hibernatetemplate ht) {
hibernatetemplate = ht;
}
// use hibernatetemplate to access data via hibernate
public foo getfoo (integer id) {
return (foo) hibernatetemplate.load (foo.class, id);
}
}然后,以
xml里的元素作为桥梁具体描述容器怎样在运行时得到服务对象并将其注入到pojo里。以下是一个
xml例子,具体描述了将一个数据源绑定到一个
hibernate session factory,然后从
hibernate session factory到
hibernate template object,最后从template object到应用的pojo。
spring代码如此复杂的部分原因是因为我们须手手动注入后台
hibernate plumbing objects。而
ejb3.0 entitymanager是自动被
服务器管理和配置。这又将我们带回到
spring并不像
ejb3.0那样高度与服务整合的论点上。
<bean id="datasource"
class="org.springframework
.jndi.jndiobjectfactorybean">
<property name="jndiname">
<value>java:comp/env/jdbc/mydatasource</value>
</property>
</bean>
<bean id="sessionfactory"
class="org.springframework.orm
.hibernate.localsessionfactorybean">
<property name="datasource">
<ref bean="datasource"/>
</property>
</bean>
<bean id="hibernatetemplate"
class="org.springframework.orm
.hibernate.hibernatetemplate">
<property name="sessionfactory">
<ref bean="sessionfactory"/>
</property>
</bean>
<bean id="foodao" class="foodao">
<property name="hibernatetemplate">
<ref bean="hibernatetemplate"/>
</property>
</bean>
<!-- the hibernatetemplate can be injected
into more dao objects -->
虽然,
spring里基于
xml的依赖注入语法复杂,但却功能强大。你可以将任何pojo注入到另一个pojo,包括你自己在应用定义的那些pojo。假如你想在
ejb3.0应用中用
spring的di功能 ,你可以通过jndi把一个
spring bean factory注入到
ejb。在一些
ejb3.0的
应用服务器里,厂商可能会额外定义非标准的pojo注入api。一个很好的例子就是
jboss microcontainer。它比
spring更一般化,因为它处理
aspect-oriented programming(aop)的依赖。
结论spring和
ejb3.0虽然都是为了向企业服务提供耦合松散的pojo,但是使用了不同方法来达到这个目的。两者都大量地使用了依赖注入。
对于
ejb3.0,基于标准的方案、注解的广泛使用、与
应用服务器的高度整合都使得
ejb3.0拥有更好的厂商无关性,更高的开发效率。依赖注入和集中的
xml配置文件协调一致的使用使开发者能够构建更有弹性的应用,并且可以同时和几个应用服务提供者一起协作。
鸣谢作者感谢tephen chambers,、ill burke、andy oliver的珍贵意见。
资源spring框架(参见codezoo:
spring)
ejb 3.0
jboss ejb 3.0
oracle application server
ejb 3.0 preview
michael juntao yuan 善长于提供end-to-end的企业解决方案, 也是一个移动方面的专家,是avid这个
开源项目的支持者。