我个人的对IOC的理解

我的对IOC的理解,和EJB和Spring和PicoContainer的理解:
1:EBJ属于IOC 的type2(set*和get*)类型和type3(constructor)类型,但是EBJ的IOC原理存在着一定缺陷:
(1)EJB容器的IOC实现的方向是查找,而且是用重量级的JNDI来查找,不管是否
在同一个jvm内运行(也就是说哪怕你用LocalHome接口来定义LocalEBJ)
但是管理依赖关系的是用JNDI查找方式,性能必然出现一定损耗.
(2)同时,JNDI查找返回的Object类型,是一种弱类型。
(3)EJB选择JNDI查找的策略,同时是他一个可测试性一个弊端,因为JNDI在测试
中,比较捆拦,导致为什么EBJ的测试如此困难的一个原因。
(4)EJB的IOC必然要检查NamingException错误,这样的代码就会对系统等代码进行
复杂化,同时并没有很好实现开关的原则。

2:Spring和PicoContainer也是可以实现IOC 的type2(set*和get*)类型和type3(constructor)类型,
他们相对的来说是纯java代码实现的没有依靠JNDI查找的策略,而是用DI(依赖注入)的方法策略,从而
避免EJB的一些缺陷,但是也同时带来一些新的问题,例如他们比较是需要更多代码量需要自己编写,例如
事务管理,日志等等,他们经常依靠java的反射机制来实现,那么回来一些反射中出现运行时类型检查问题。

3。两者谁更可取呢,我不敢给大家断言,因为各有一定优势,但是Spring和PicoContainer的问题可能对我们
更容易解决,采用AOP的方法可以解决一些问题,同时对Spring和PicoContainer的系统比较容易和遗留或外界
系统集成和扩展。

分析很精辟,因为IoC模式有很大的优点,所以,EJB 3.0将采取Ioc代替JNDI,从而实现容器外测试。

所以,设计思想可以对技术有很大的推动,有先进的思想指导,才有先进的实践,Spring/PicoContainer率先实现了IoC先进的思想,但他们也只是先进思想的一个实现产品,EJB 3.0因为需要标准委员会讨论,延误时间推出,但是不能说EJB 3.0是学习Spring/PicoContainer,甚至武断说:EJB 3.0就是Spring/PicoContainer+XXX,这种说法是可笑的。

这就象美国在先进科技和思想指导下最先研制出原子弹,而中国过后也在同样的科技思想下研制出原子弹,那么就说中国的原子弹是学习美国原子弹,或者说就是他那个样子。

先进的设计思想+新的语言特性==Java世界的技术革命。

感谢对于板桥大哥的提示,其实我并不是反对EJB的人,我对EJB的发展还是甚有期望的(只是说出EBJ2.0的一些思路和实现的随着技术的革新的确更容易浮现一些内在缺点---这是好事情),毕竟曾经对EBJ的研究中学习了很多的先进的思路和模式的提炼,而且EBJ曾经对J2EE起了很大推动的作用还有很多系统中使用了EJB(遗留系统)。我们要以客观的心态去对待技术问题,我们工作上采取那些技术并不能因为个人的感情去决定一个系统的框架的形式(除非是个人兴趣研究除外),而应该从需求和成本问题来决定(需求和成本驱动)。其实我发表着篇文章就是希望能抛砖因玉,希望更多有认之士能互相交流,毕竟还有很多象我这样水平一般的人希望对世界上比较流行的框架思想感兴趣和想研究的。稍后我将和大家谈一下我个人认为AOP在Spring和PicoContain的作用,希望大家一起来讨论。

今天我就这个话题和网上一个朋友在QQ上进行讨论,讨论的观点属于个人观点不一定正确,如果发现有不当的地方请指出来(谢谢):

2004-09-21 10:07:35 小兵
我认为对于ejb的接口的评价不是很准确,它的设计主要不是为了本地的调用,更大的方向应该是对分布式环境的支持,这样的话它才有其意义。
个人认为ejb在国内的使用不是很正道,总是为了用而用,或者是为了某种商业目的。


2004-09-21 10:06:08 recher
首先我承认EJB开发目的:不是为了本地的调用,更大的方向应该是对分布式环境的支持.我只是举例子,如果说本地和远程接口的比较,我更反对本地接口--缺点就更多了,更明显了.对于分布式的问题可以用纯java的DTO(RMI)的机制实现你的问题,你注意了接口的编程是很好一种方式,我从不反对甚至我追求接口编程,但是我说的是EJB容器对的接口的实现和其在内部耦合关系的思路有问题.

2004-09-21 10:21:08 小兵
对于不同jvm也可以吗?这点我不是很了解。

你说的内部耦合有什么问题?在文章中没看到啊。

2004-09-21 10:20:12 recher
首先,你要清楚,IOC的机制是:---处理类之间和接口之间或类与接口之间关联关系,根据好莱坞原则,调用着与被调用者的主次关系,实现开关的原则.类之间可以很好(甚至)可以完全避免耦合,一个类只负责自己逻辑功能代码,如果想调用其它类告诉IOC容器去做(一种比较好的方式是根据配置文件来设定复杂关系),而不需要在代码上过多的编写.

2004-09-21 10:37:25 小兵
然后呢?

2004-09-21 10:34:53 recher
这样说吧:IOC应该用更流行的术语叫DI(Dependency Injection---依赖注入)看到这个名称你就知道他的功能

2004-09-21 10:46:02 小兵
我知道呀,我有看过这方面的资料
我只是不认同你说的ejb的接口的问题

2004-09-21 10:44:50 recher
EJB的问题并不是接口产生的,相反的一些好处也正是依靠面向接口的方式;EJB的缺陷在于它的内部实现机制的思路上.

2004-09-21 10:45:21 recher
正如板桥大哥说的:理解Spring/EJB 3.0之类先进技术,须首先掌握指导他们实现的先进的设计模式,再次证明:设计模式是 Java学习不可逾越的鸿沟,否则就会走向错误的方向。

2004-09-21 10:55:35 小兵
(2004-09-21 10:44:50) recher
EJB的问题并不是接口产生的,相反的一些好处也正是依靠接口的方式;EJB的缺陷在于它的内部实现机制的思路上.

你可否举例说说ejb的缺陷,并说说如何解决该缺陷呢?

2004-09-21 10:56:49 recher
我晚一点再说吧,EJB的缺陷最少有5种,每一种都来自实现机制.如果是代码或技术产生的问题对于EJB 来说就不叫缺陷只能说不足,因为容器商肯定可以解决.但是如果思路有问题,就要重构了,毕竟它的EBJ接口就必然体现它实现机制思路,正如板桥所说EJB委员会正以现代IOC思路机制来实现,到底变成什么样子?--我也想知道(更希望能为我们带来更好的实现方法).

2004-09-21 11:11:17 recher
EJB2.0的编程存在以下问题:1,不能实现测试驱动开发---可测试性极差。2,既然EJB的提供了LocaleHome的接口为什么还是在内部使用JNDI的机制呢。3,EJB容器的服务是强加的,不管发布在容器内的EBJ用不用到一些服务(例如安全,事务,等)都在监听,但是现在的一些机制已经实现谁要服务向IOC容器提出申请,IOC容器就可以对要得服务进行动态加载,IOC服务就像ClassLoad,当然也是可以实现缓存的机制和对象服务池的机制的.4,最要命的是现在2.0的机制根本上牺牲了OO,代码颗粒度很难或不能分得很细,就更不要说支持AOP了。5,性能的缺陷,其实在POJO的实现比EJB的实现快.6.这只是我的猜测:EJB的SessionBean的实现依靠了servlet的功能,如果真的是这样的话会引发一些逻辑层的生命周期放到表示层中的现象了。

2004-09-21 11:19:19 小兵
哦,你要说ejb的缺陷的话,那可多的是了,但我看你的问题应该是集中在如何调用这个环节上的,这也是你说的ioc所致力解决的问题--如何组装,如何提供服务。但在这个环节上ejb的做法也有其道理呀,顺便说说,ejb应该不是“EBJ属于IOC 的type2(set*和get*)类型和type3(constructor)类型”,应该是type1吧。

2004-09-21 11:22:45 小兵
你是用哪个容器来跟ejb容器比较的?这是你理想中的容器吗?

2004-09-21 11:19:13 recher
tyep1,是对象化;EJB在一些实现IOC应该支持type2和type3的,EJB的接口中还是存在一些反映支持IOC的类型.但是EJB还是以set*;get*.EJB解决内部关系的机制现在看来已经不具备优势.成了发展的绊脚石.缺陷和不足是不同的.坦白说现在还没有我理想容器出现,因为我永远不满足除非世界的需求一成不变。如果问我比较喜欢那一个,我现在会说:Spring---因为它比较绿色.关于Spring 又是一个很大讨论话题,以后再说它吧.

2004-09-21 11:29:46 小兵
type1不是:Interface Injection吗?


2004-09-21 11:27:17 recher
对阿,就是对象,JVM中Interface是没有实例的.只是用了Inteface来对外封装一层;----这就EJB的接口编程机制的一个值得提倡的事情.

非常精彩的对话,我想回答一下你这个朋友的一个问题:
“看你的问题应该是集中在如何调用这个环节上的,这也是你说的ioc所致力解决的问题--如何组装,如何提供服务。但在这个环节上ejb的做法也有其道理呀,”

调用这个环节大家都是一致的,如果说他们都属于IoC模式有些让人疑惑,可以说他们都实现了Registry模式,所有组件都向Registry注册一下,调用者只需从Registry寻找服务即可。Registry模式是大型系统架构模式。

EJB 2.0的调用,首先从Registry处获得一个Home接口,这其实是一个工厂,再从这个工厂创建EJB实例。其实完全可以将Home工厂和JNDI合并在一起,直接从Registry处获得EJB实例,我去年设计的JDONSD框架中就实现了这种调用方式,可以下载estore演示源码或<<Java实用系统开发指南>>EJB方法调用章节,具体代码如下:

//从Registry处获得EJB本地实例
ProductManagerLocal productManager = (ProductManagerLocal) sf.getService(FrameworkServices.ProductEJB, request);
//直接使用EJB实例
Product product = productManager.getProductById(keyValue);

我想EJB 3.0的调用也会这样简化。因为可以这样简化了。


你以为规范委员会没想到这些问题吗?
这是设计模式的问题,从设计上讲,这种分离是优雅的,就像接口狂一样,为各种不同情况设计一大堆方案,性能是提升了,但是整个系统的框架就会变得复杂,路线也不清洗,想想以前64M内存时写的程序框架设计思想大家肯定觉得太垃圾,ejb企业级应用,硬件将解决大部分性能问题,否则绝对别用,你那pc台式机来狂扁ejb有什么意义呢。就是走个jndi而已,那大家变成还要走个接口呢,这种折中方案没必要讨论,觉得不好就自己来一个也没人反对!不同需求资源,自然解决方案不同,但是从设计框架上来说ejb针对企业级应用,分布式应用。。

我看了大家的讨论,我觉得对IOC等关键是明白它的核心思想,若是实现自己AOP不用Spring等也可以实现,主要是利用java的反射机制就可以。但是不用ejb的化的企业级应用的分布式因为没有容器的支持,分布性等实现起来相对复杂一些。我认为Ioc比GOF的工厂模式,好多了。我发现板桥大哥喜欢用工厂模式,而很少用IOC。

要解决分布式,在java的基本技术和目前大家的支持来看只能jndi来解决。看来,这还需要我们对jndi,java反射等这些基本的原理再深入理解下,一些其他的性能,优缺点,自然就可以推论出来。

这样理解IOC可以么?

以前我们都是调用一个函数
test(a, b, c); 是先找到函数,然后塞给它a, b, c.之后盼望结果。

现在是
先找到a, b, c这些参数。
然后把抓到test函数,叫它把这些参数搞定。

请指教。

奇怪,我觉的ioc的思想非常自然简单啊。为什么会有这么一堆的讨论。说白了就是要某个东西的时候,就自己去取一下就行了。而这些通过类反射,动态代理等是很容易通过配置的形式实现。以前被老外骗说类反射什么的对性能影响有多大,连cast都很谨慎的用,更别说class reflection。但到现在,别说这些了,连使用cglib动态产生类老外都说性能很好,不会对系统有什么影响。当然他们也给除了理由,jdk1.4及以后对class reflection等有了很大的改进,性能上已经不是瓶颈,再加上利用cache等机制,就完全可以放心使用。哎,真是成也小何,败也小何啊。

周末给同事讲了一下spring,ioc.才发现要说明白不是很容易,特别对没有oo设计基础的。我说spring是一个ioc容器,就是应用程序只需要知道要调用的接口,而不需要知道其具体实现。从ioc/di的概念来讲,是将注入接口的具体实现的步骤转移到调用的客户端。比如a,b,c三个类,
ic为接口,c实现ic.在b里要调用ic的实现。a是调用b的客户端,那么就把c的实现在a调用的这一步骤注入。
而在spring这个容器中,更把这个任务简化到通过配置文件来标注。看着还没有被理解,我本来打算换个角度来说,spring的ioc容器是面向方面的一个另类实现,就是把注入接口的实现的这一个aspect提取出来,由spring来统一实现(通过配置文件)。但想想这样一来,恐怕又对aop来解释不清了。其实我个人觉的,架构的事是由架构设计师这一角色的人来负责,风险当然也是由他们承担。而没有必要每个人都懂架构。而学会如何使用架构这一套模式的重复性工作即使由只有一点经验的程序员来学也是非常快的。毕竟我们程序员干的就是重复性的劳动很多。所以这是我们的本能。

dabb两次观点都很有意思,Ioc体现了大道至简,但是要表达出来,却是相当不容易的,我一般给别人讲解Ioc,总是从基本的GoF设计模式开始,而且需要使用实例对比演示出 使用Ioc前后的效果以及目的。

目前我又有一个心得:从我refactoring Jdon框架经历来看,Ioc模式和XML配置开发是密不可分的,如果说以前我们使用Xml配置,是因为觉得配置开发方便灵活,可自定义;但是从程序编写上好像没有这个必然要求,但是当你使用Ioc模式;而且组件管理完全使用Ioc后,就必须使用Xml配置了,各个组件都向Xml配置负责,否则,向Ioc容器注册这一过程就很琐碎,属于非OO。将来所有的过程性东西都可以放到配置里去了,Java程序只有纯OO了。

瞎说一番。

参考文章
依赖注射 :垃圾回收机制的镜像
Dependency Injection -- the mirror of Garbage Collection

作者使用垃圾回收机制做比喻,通过引入这个机制,解放了开发者,开发者不用再照顾垃圾回收这个问题;而Ioc则起到同样效果,开发者不用再关系对象之间依赖了,只管使用就可以了。