论坛首页 Java企业应用论坛

论Spring与EJB的组件架构

浏览 53276 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-09-20  
赫赫,我来说一下spring vs EJB,首先强调,我不是ejb的拥护者,但我欣赏他的完整、他的学院气,同时也深感他的硬伤,我不是spring的拥护者,虽然去年3、4月间看到spring的时候曾经让我眼前一亮。对ejb有太多的误解,对spring有太多的吹捧,我希望这是一个相对公平的比较.

  我认为spring和ejb的差异在这样三个方面,一个是受众也就是这两个叫framework也好叫platform也好的东西的scope;另一个是component architecture,最后一个是语义。

1.Scope比较

  先说scope,ejb的scope是什么?ejb针对什么系统来设计的?这个我想一个人一个答案,我说了不算,同样大家说了也不算,我们来看规范(题外说一句,我想本来我没啥资格在这里谈论ejb,我应用ejb的项目不多,但是我有个习惯,就是读规范学技术,不管别人怎么说先看这个东西是怎么来的,我想这一点还使我有些开口的自信,不至于太贻笑大方),ejb规范的头几句:
Enterprise JavaBeans is an architecture for component-based computing.Enterprise beans are components of transaction-oriented enterprise applications.

  好了,很明确,ejb是针对transaction-oriented enterprise application的组件,那么也就使说ejb是面向以事务为中心的企业软件,而不是别的。ejb的核心是transaction,不是domain model或别的。
  why transaction?我在电力行业做过一阵信息化软件架构师,在电力这样一个需要处理大量数据的领域里,很少有oo model,而是做完entity分析,交给dba去优化,以数据性能为主,这样的系统里,数据操作的粒度就是transaction,而不是object或是别的。我想这该算是一个大型企业级系统,我看到的是transaction,因此ejb这个把scope定在enterprise级的东西而言,这样的设计还使合理。而且ejb对transaction这部分的处理确实比较完整,cmt,bmt,不同的transaction scope控制的都很好。基于这种认识,我认识transaction script是ejb的标准应用模式,而不是domain model或是别的。
  这是对ejb最大的误解的来源,我看过的所有ejb书里,只有o'reilly的一本隐约提到transaction是ejb的中心。其他一律不提,疯狂的鼓吹ejb多好多好ejb多么万能,我想,如果不知道ejb是transaction-oriented的,那么ejb奇怪的对象模型的确不可接受。

  再说spring,spring是什么呢?我没有看到特别明确的定义,不过我想仿照ejb,定义spring为:
Spring is a Javabean-based framework that supporting component architecture development.Spring provides  lighter context for heterogeneous entrprise application.

  我e文很差,cet-6 6次都没过,我想说明的是,spring是一个轻量化的组件架构,可以支持多种企业应用程序模式.看到这里有人又该说了,no,no还有ioc,还有aop,没错这些很cool的特性我没说,但是包含了,component architecture意味着两个方面,component working(编写组件)和container working(编写容器环境),spring的ioc和aop是用在container working里的.当然肯定还有其他的一些没有概括,但是我想主体我还是说到了的.这样scope就很明确了,spring的基础是javaBean,javaBean支持完整的oo建模,因此spring可以适用更多的结构,domain model和别的一些。

那么开始比较,spring有一个理论上普适的组件模型,但是鉴于大型应用多为transaction-oriented,那么用spring的理由就是domain model,ejb不能提供完整的oo模型而spring可以。

结论:由于scope不同,其实比较spring和ejb那个更适合企业开发没什么意义,因为这里面根本就是两个不同的范畴,在scope上指责ejb不如spring,就好像说raimundox,你就不能替老婆把孩子生了,还让她那么痛苦的怀胎十月。其实我也不想,我也想替,可惜我们这功能.....扯远了,ejb也是,没这功能你怎么强求他呢?你要说ejb设计的不好,也不对,人家有专门的领域。因此我说,在scope上比较spring和ejb没意义,根本不是一个级别的。

2.component architecture

  Component architecture有一个基本观点,就是component和context的分离,理想情况下,component只负责业务的实现,而container提供context,这个context只技术context,比如事务比如安全的支持。于是,component architecture的基本观点就是business关注点和technique关注点分离,business由component负责,technique由context或者叫container实现。那么很明确了,component architecture里有两种编程,针对component的和针对container的。
  好,有了这个理解,我们可以继续了,如果有人有疑意,那么抱歉,这片文章并不适合您,后面全部的论点都是基于这个观点的,如果不认可这个,下面的也不会认可,您也不用浪费时间了。

  首先看ejb的component方面,ejb在component architecute做得非常的好,ejb就是一个业务组件,在container-managed的情况下,组件通过声明可以应用容器提供的技术context,当container-managed不满需要的情况下,可以bean-managed,只要保持对外的事务语义就可以了(记得吗?ejb是transaction-oriented,事务最重要)。在ejb里,组件和容器的约定非常明确,哪些需要组件写,哪些是容器提供的非常明确,这是component architecture里很好的习惯,明确组件和容器的界限(ejb的一个缺点,矫枉过正,有一些操作也被禁止)。编写代码非常容易,业务,only业务。其实ejb的规范里,ejb的coder其实最好是domain expert,实现业务逻辑就好了。

  现在来看spring的component方面,spring以javaBean为基础,贫容器,也就是对容器没要求,于是,spring第一个缺点,contianer和component的约定不清晰(写到这里我已经听到一些人在叫了,这是spring的优点,自由,别急,后面我会证明这是spring的软肋),但是spring用了一种比较聪明的办法,那就是加强container working.

  看一下spring的container working,通过spring的aop api,我们可以很容易的为特定组件定制容器环境,把一个组件需要的容器技术环境以aspect的形式weave到component里,非常的灵活,也非常的强大,spring通过这种形式来弥补组件/容器约定不足的情况,一切由component选择,容器除了装配(ioc/dip)不提供任何技术context,想要什么自己来,这个给了component实现者自己选择的权利,很好(但也隐含了spring的最大的不足,别急我后面会说)。

  再来看ejb,非常遗憾,ejb container working的能力几乎为0,当然算上jca的话还不算太差,但是那只是资源,而不是技术context。why?因为ejb认为他已经提供了所有企业级开发所必需的技术context了,事务(ejb里我总把他放在第一位)、分布、并发、安全等等。在ejb看来container working的能力几乎无用,而且不安全,除了jboss开放了比较多的container working接口其他的ejb container提供这方面的支持很少很少.当然提供很多技术context并不是坏事,要命的是不能配置,要么全用要么不用(倒是很原子),这是ejb最大的不足,容器环境不可配,也是spring强于ejb的地方。

  上面我们已经看到了spring和ejb都是component architecture,那么component能想到的最直接的用处就是复用。那么比较这一点就是比较ejb和spring component architecture的关键。看到这里spring的支持者们该常出一口气了,spring复用一定强于ejb复用,赫赫,但我的结论正好相反,ejb复用优于spring复用!!收起你们的愤怒,收起你们不屑,听我把话说完。

  在component architecture里,component是业务实现,而不该有技术代码,就算用也要通过容器环境去和容器交互来完成操作,比如ServletContext等东西。那么其实组建结构下复用的关键不是组建而是容器!!

  以前有一个颇有名气的dx(gigix别看了,说你呢),说"COM和EJB都鼓吹模块化和复用,模块化是真的,复用是骗人的",com我不是很熟,不好下结论,ejb呢?ejb不易复用我承认,但是骗人吗?不骗,后面我给出一种ejb复用的思路大家参考。反正组件一点技术都不作,只有业务逻辑想用就要有相应的容器环境,那么容器环境的复用性才是组件复用的关键。ejb不易复用是因为如果脱离容器,我们就必须给它提供相应的技术context,事务、分布、并发等等一个也不能少,因此容器外复用ejb效率很低。注意,是容器外,组件本来就是跑在容器里的,谁让你非要拿出去用),而容器内呢?因为ejb规范规定ejb容器应该兼容,别说webSphere到bea的移植有多难,其实不难,或者说难度比把spring组件移植到pico复杂一点,当然你用vendor-specified的特性就没办法了,这不再规范内,你违规就别怨人家。因此,ejb的复用是可以的,而且是规范保证的,容器外也有办法,也不是很难,我后面说。

  再看spring,的确他很灵活,但这正是致命伤,component完全是业务实现,但是容器呢?spring怎么保证容器的环境?没有,只能你自己保证,当你沾沾自喜的说,spring里的component都是pojo,可以很好复用的时候,可曾想到,这复用的代价是要复用容器。比如有个componentA,在SystemA里需要事务模型A和安全模型A,在SystemB里需要事务模型B和安全模型B,当你从SystemA里复用componentA的时候,你要怎样?重写事务模型B和安全模型B,然后你可以堂而皇之的说,你复用了组件。的确,你复用了组件,但是你重写了容器,值吗?更可怕的是,spring容器和组件没有约定,那么怎么保证你的组建不写技术代码?ejb只要Bean-Managed并提供统一的事务模型就好了,spring呢?你靠什么保证?你自己?这是spring一大硬伤,完全container-managed下缺少特定的component边界控制.你可以说,特殊要求的事务模型ejb还实现不了呢,的确,这是有可能,但是ejb transaction model不能适用的情况有多少?如果真的不行,只能说ejb的简单复用在这里失效。

  对于组件还有一个问题就是部署,这也是ejb为人诟病的地方.的确,ejb的部署够复杂,但在ejb规范里有一个专门的角色来负责部署的,ejb是component architecture,那么比如有一个人来粘合技术和业务,这个人不该是programmer(我刚才说了,ejb的实现者最好是业务专家,实现业务逻辑),ejb的部署才是很厉害的人,他需要知道什么业务需要什么样的技术支持,该怎样得到性能,因此deployer才是ejb architecture里最牛的,我重来不以为写ejb的是高手,但是一直都敬仰ejb的deployer.当然这里有一个调试困难的问题,这是ejb的硬伤,没办法,这甚至是组件开发的硬伤.
  再来看spring,spring宣称他部署简单,我觉得rod johnson在转移视线,想想看,打成一个war和打成一个ear有多大的区别?那么部署的差异在哪?差异在ejb的deploy description和spring的context.xml的编写上!在用spring开发中要有一个人来写context.xml这个人往往比较了解系统,知道什么组件用什么拦截,那个组件依赖那个,甚至会是架构师在作这件事情,那么和ejb里对系统有大局观的人来做deploy有多大区别?可能就是Xml的编写吧,我想在工具的支持下就是熟练度的问题,因此我觉得部署上spring和ejb差不多,spring不用启server,调试放便些。

  结论,在component architecture上,spring灵活,ejb统一完整,各胜擅长,spring的灵活以降低复用为代价,但是如果有common的技术实现,的确很好复用,但是spring+一套common的技术实现也就约等于ejb了吧?

3.语义

  那么spring复用的问题表明了什么呢?其实是缺乏语义的支持,ejb开发可以看作在一个统一的语义环境下来作的,这个语义由ejb规范规定,因此ejb的复用有语义保证,而spring呢?贫语义,一切都要开发者自己来实现。因此,如果ejb的环境语义可扩展并且可配置(比如去掉分布),那么spring毫无优势,标准的一致的完整的组件架构使ejb会大有作为,但是现在并没有,才有了spring的火爆.这是一种畸形的胜利,完备语义的输给了贫语义的,问题是什么,强迫消费...谁让ejb非得强迫客户去买用不到的分布式环境的单?但是统一语义的威力不会因此掩灭,现在有两条路,spring联合os社区,制定lightweight j2ee语义集合,争取成为标准。第二,ejb实现技术语义可配置可扩展。谁会胜利?不好说,但是似乎ejb的脚步快一些!

附:容器外复用ejb

其实ejb在容器外完全是可以用的,但是为了最大限度保证能用,bean-managed是推荐(不是cmp,bmp而是cmt,bmt),那么怎么传送一个transaction进去?SessionContext(好像是这名记不清了,都快2:00了,困呀...就是ejb那个context接口),一个接口嘛,自己mock一下,给一个transaction进去就好了。怎么装配?spring的setter injection。如果用spring,那么cmt也可以实现,拦截啦,不过就看能不能实现ejb transaction model了。entity bean,如果是bmp,就用它好了,cmp,继承一个上hibernate。这些都模拟好了,找一个in memory的jndi,把spring context封进去,这样相当于我们用spring实现了一个lightweight ejb container(其实就是给spring一个ejb api的皮),轻到什么程度?除了注射什么都没有。
然后client就可以构造jndi,然后lookup了
看到这里一定有人说,你吃饱了撑的,这么费劲容器外复用ejb,为什么不直接用spring,这样也不够pojo,每个组件都有ejb的类的继承,好,我告诉你这么做的好处,首先,虽然不够pojo,但是足够bean,因此spring来管理ejb是可以的,证明我的观点容器外使用ejb可以(赫赫,不要说偶rpwt...).其次的,当业务发展了,你的系统需要分布了,把spring去掉,拿出ejb,redeploy,ok了,延展,稳定,分布都有了,这才是复用该有的境界,改一个部署整个环境换掉,去掉lightweight的ejb container,换乘heavyweight的就是重量级。
当然这么实现很难,在ejb3里会容易些,我敢打赌,spring以后一定是lightweight ejb container的供应商,免不免费,os不os要看rod johnson了,不过我觉得希望不大。

致谢:

首先感谢dlee,在和他的讨论中形成了这篇文章的主题,然后是冰云,他帮我审稿直到2:04,udoo,perhaps都提出了中肯的意见,谢谢他们.

当然也欢迎大家访问我的blog:www.cnblogs.com/raimundo
   发表时间:2004-09-20  
关于复用性,根本就不需要讨论,限制越少,复用性就越高。不管怎样去讨论问题,EJB永远不可能比一个普通的JavaBean更可以复用。也就是说,如果Spring是谎言,那么EJB就是扯淡了。

如果你的程序模块或者框架真正被n个人或者n各不同的项目组复用过,你就会知道不对体系结构作任何限制是多么多么的重要。如果你真正编过一些复杂的框架,你就会知道天马行空、不受拘束的对象建模和实现是多么多么的必需。

有一个不是直接有关的话题。我对目前有多少可以黑箱重用的业务组件持非常怀疑的态度,相反,可重要的工具箱,可白箱复用的框架是我认为目前最现实,也是提高生产效率最有效的途径。这也是我从5年来对组件认识的一个变迁。我认为软件工业现在还只是发展到这个阶段,甚至在一定范围内只能发展到这个阶段,因为软件是软的,一个在非常大范围内可以黑箱重用的组件(例如CPU)会变得非常复杂,而不能像CPU一样只需要几个简单的接口标准就可以插到任何主板上。



我也不理解什么容器的复用性比组件的复用性更重要这样的结论。

如果不要部署就可以实现需要你所认为最最牛的部署的人的话,我为什么还需要部署。

我认为讨论谁好谁坏没有任何意义,有意义的是讨论什么情况下适合什么情况下不适合?

接下去就是讨论你这个项目该不该用EJB,我的结论是
只有在需要分布式业务处理的系统中,EJB才存在着价值,因为其他的东东(例如分布式事务、ORM)我现在已经直接可以使用非常成熟的单独产品了,唯独在分布式Java对象这一块上,EJB还是具有它不可取代的优势。所以要用EJB也只需要用它的SessionBean即可。
0 请登录后投票
   发表时间:2004-09-20  
spring的这个不叫贫语义,而是贫规范。
语义是个什么东西?没有语义,spring这个东西怎么转?那么多用spring的人怎么在用?大家都是瞎子摸象?想了解语义,直接看代码是最简单的方法,懒一点的话可以去读reference,但是要冒上一点不同步的风险。
从规范的角度来说,spring和ejb的区别只在于ejb现有规范再有符合规范的实现,而spring是先有实现,当稳定到一定程度,并且被社区广泛接受(这个只是一种可能性而已,呵呵)以后,才会有规范出现。
从这个角度来看,所有偏离sun的导向的工具,比如hibernate,都是贫规范的。
0 请登录后投票
   发表时间:2004-09-20  
贫规范有什么关系呢。如果容器只要求Java Bean,别的规范有没有就无所谓了,反正Java Bean是所有人都认可的规范。

楼主这个文章真没意思,不想反驳。
0 请登录后投票
   发表时间:2004-09-20  
楼主跟我们一般的“复用”概念是不一致的!
讨论起来,估计将会是一场大战。
容器内的复用不依赖任何外部容器的复用 是完全不同的概念
楼主的:
component architecture 这一部分就暴露了楼主对于“复用”概念的理解偏差!

你说EJB的Bean可以跟Spring的POJO相比,那么请你看看EJB的sessionbean的超类是什么!这个超类是干什么用的!(继承也是依赖,别忘了哦)
至于说,事务,安全,等等。这些固然是EJB的特点,但如今这些咚咚都有了轻量级的开源项目支持,以后,EJB的这些优势也会逐渐失去。
0 请登录后投票
   发表时间:2004-09-20  
重申我在《剖析EJB》里说过的一句话:

“从EJB到EJB的‘移植’,难道你不觉得这是个笑话吗?”
0 请登录后投票
   发表时间:2004-09-20  
gigix 写道
重申我在《剖析EJB》里说过的一句话:

“从EJB到EJB的‘移植’,难道你不觉得这是个笑话吗?”

哈哈,确实有点可笑
不过,似乎,看起来,好像 楼主在讨论从此EJB容器移植到彼EJB容器的可行性哦! 这个此彼还是有点区别的哦,比如说vendor不同,价钱不同,大小不同等等。
最后还是想 一下
0 请登录后投票
   发表时间:2004-09-20  
potian 写道

如果你的程序模块或者框架真正被n个人或者n各不同的项目组复用过,你就会知道不对体系结构作任何限制是多么多么的重要。如果你真正编过一些复杂的框架,你就会知道天马行空、不受拘束的对象建模和实现是多么多么的必需。


正因为我做过框架,也做过架构,所以认为做框架或者架构第一件事情就是约定,那些框架作,那些框架不做,因此我虽然认为“天马行空、不受拘束的对象建模和实现”是必须的,但是必要的框架约束是不可以避免的。我强调的是组件和容器间的约定,而不是对建模的约束。一开始我就说了,ejb只能很好的支持transaction-oriented的建模,而spring是什么建模都可以的。但建模约束!=容器对组件的约束。容器对组件的约束是哪部分归谁写的问题,而不是建模问题。

potian 写道

有一个不是直接有关的话题。我对目前有多少可以黑箱重用的业务组件持非常怀疑的态度,相反,可重要的工具箱,可白箱复用的框架是我认为目前最现实,也是提高生产效率最有效的途径。这也是我从5年来对组件认识的一个变迁。我认为软件工业现在还只是发展到这个阶段,甚至在一定范围内只能发展到这个阶段,因为软件是软的,一个在非常大范围内可以黑箱重用的组件(例如CPU)会变得非常复杂,而不能像CPU一样只需要几个简单的接口标准就可以插到任何主板上。


大部分同意,我想强调的是容器环境(也就是技术或者“可重要的工具箱”)对组件复用的重要。当然我的理想还是黑箱复用。

potian 写道


我也不理解什么容器的复用性比组件的复用性更重要这样的结论。

如果不要部署就可以实现需要你所认为最最牛的部署的人的话,我为什么还需要部署。


容器复用比组件复用重要,因为这是component architecture的约定,容器提供的组件就不会写,那么没有容器环境组件的逻辑就有问题,不可能希望在一个不提供事务支持的容器里复用声明性事务的组件吧?组件架构规定了什么约,那么复用就要提供什么约。

至于部署,我不知道potian部署的含义,我指逻辑部署,比如spring cotext.xml的编写,以及ejb deploy description的配置,jndi装配等。我想可能是我没说清楚吧。
0 请登录后投票
   发表时间:2004-09-20  
to:raimundox

很不错的文章。

说说我的看法:
1、组件与容器,必须是伴生的,组件的复用性,不是由组件决定的,而是由容器决定的。

2、效率来自于限制,越是明确的限制,越是能提高开发效率。对于开发人员来说,如果只给他一种选择,那么他就不会浪费时间,去考虑其他选择。

3、在两种不同的容器之间,谈论复用没什么意义,比如从EJB到Spring,或者从Spring到Pico。即时只是泛泛而谈,也非常复杂,更何况一个真实的项目,你想要移植过去,简直就是“寻死”。

4、EJB的复用性差,不是因为他的限制太多,而是因为他的限制太少。他只对技术实现规则进行了限制,而没有对业务逻辑进行限制。当然,这个事情也不该通用的EJB容器来做。

5、但是要真正提高一个组件的复用性,就应该将应用建立在“业务逻辑框架上”,而不是直接建立在“EJB容器上”,这样直接建立在EJB容器上的EJB,就像在WEB层,完全、直接的使用JSP和Servlet和WEB容器打交道。那样的代码,复用性当然为0。

6、归根结底,脱离具体行业、具体领域,泛泛而谈EJB的复用和Spring的复用,没意义。
0 请登录后投票
   发表时间:2004-09-20  
charon 写道
spring的这个不叫贫语义,而是贫规范。
语义是个什么东西?没有语义,spring这个东西怎么转?那么多用spring的人怎么在用?大家都是瞎子摸象?想了解语义,直接看代码是最简单的方法,懒一点的话可以去读reference,但是要冒上一点不同步的风险。
从规范的角度来说,spring和ejb的区别只在于ejb现有规范再有符合规范的实现,而spring是先有实现,当稳定到一定程度,并且被社区广泛接受(这个只是一种可能性而已,呵呵)以后,才会有规范出现。
从这个角度来看,所有偏离sun的导向的工具,比如hibernate,都是贫规范的。


贫语义这里指贫技术语义,spring没有提供任何的现有技术语义,而把这部分交给developer自己去处里。我说spring贫语义,不是说他没有语义。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics