我们知é“åQŒåœ¨JavaåŸºæœ¬æ•™ç¨‹ä¸æœ‰ä¸€ä¸ªå®šå¾‹å‘Šè¯‰æˆ‘们:所有的对象都必™åÕdˆ›å»ºï¼›æˆ–者说åQšä‹É用对象之å‰å¿…™åÕdˆ›å»ºï¼Œä½†æ˜¯çŽ°åœ¨æˆ‘ä»¬å¯ä»¥ä¸å¿…一定éµå¾ªè¿™ä¸ªå®šå¾‹äº†åQŒæˆ‘们å¯ä»¥ä»ŽIoc容器ä¸ç›´æŽ¥èŽ·å¾—ä¸€ä¸ªå¯¹è±¡ç„¶åŽç›´æŽ¥ä‹Éç”¨ï¼Œæ— éœ€äº‹å…ˆåˆ›å¾å®ƒä»¬ã€?/p>
  ˜q™ç§å˜é©åQŒå°±å¦‚åŒæˆ‘ä»¬æ— éœ€è€ƒè™‘å¯¹è±¡é”€æ¯ä¸€æ øP¼›å› 䨓Java的垃圑֛žæ”¶æœºåˆ¶å¸®åŠ©æˆ‘ä»¬å®žçŽîCº†å¯¹è±¡é”€æ¯ï¼›çŽ°åœ¨åˆæ— 需考虑对象创å¾åQŒå¯¹è±¡çš„创å¾å’Œé”€æ¯éƒ½æ— 需考虑了,˜q™ç»™¾~–程带æ¥çš„åª„å“æ˜¯å·¨å¤§çš„ã€?/p>
  我们从一个简å•例å开始,有一个普通类B代ç 如下åQ?/p>
public class B implements BI{
    AInfterface a;     public B(AInfterface a){       this.a = a     }     public void invoke(){       /** ...*/     } }  |
  有两¿Uä‹É用B的方å¼ï¼š
ã€€ã€€æ™®é€šæ— Ioc容器的调用方å¼?
  BI b = new B(new A());//需è¦åœ¨ç”ŸæˆBå®žä¾‹ä¹‹å‰ ç”ŸæˆA½{‰å®žä¾?br />  b. invoke();
  使用Ioc容器(Jdon框架)çš„é©å‘½è°ƒç”¨æ–¹å¼ï¼š
  BI b = (BI) WebAppUtil.getService(“b�;
  b. invoke();
  上é¢ä¸¤ç§æ–¹å¼é‡è¦åŒºåˆ«åQ?br />  å‰è€…需è¦ç…§™å¾B¾cÖM¸A¾cÈš„实例化,如果B¾cÖM¸è°ƒç”¨ä¸åªA¾cÖM¸€ä¸ªï¼Œ˜q˜æœ‰æ›´å¤šå…¶ä»–¾cÕd¦‚C/D/E½{‰ç±»åQŒè¿™æ øP¼Œä½ 在使用B¾cÀL—¶åQŒè¿˜éœ€è¦ç ”½I¶å…¶ä»–类的创建,如果C/D/E˜q™äº›¾cÖM¸æ˜¯ä½ 自己¾~–写åQŒä½ ˜q˜éœ€è¦ç¿»é˜…它们的API说明åQŒç ”½I¶å®ƒä»¬åº”该如何创建?是ä‹É用New ˜q˜æ˜¯å·¥åŽ‚æ¨¡å¼ ˜q˜æ˜¯å•æ€è°ƒç”¨ï¼Ÿ
  ˜q™æ—¶åQŒä½ 会感å¹ï¼šå“‡ï¼Œæœ‰æ²¡æœ‰æžé”™ï¼Ÿæˆ‘åªä¸è¿‡æ˜¯äؓ了ä‹É用B¾cÖM¸ä¸€ä¸ªå°ž®çš„æ–ÒŽ³•åQŒå°±èŠ±åŽ»æˆ‘è¿™ä¹ˆå¤šæ—‰™—´å’Œç²¾åŠ›ï¼Ÿ
  当我们ä‹Éç”¨ç¬¬äºŒç§æ–¹å¼æ—Óž¼Œž®±æ— 需花很多精力和旉™—´è€ƒè™‘A/C/D/E½{‰ç±»çš„创建ã€?/p>
  使用Ioc容器åQŒä½ å†ä¹Ÿä¸å¿…åšè¿™äº›åƒµåŒ–æ„šè ¢çš„å·¥ä½œäº†ï¼Œæˆ‘ä»¬åªéœ€ä»Žioc容噍䏿Гå–一个类然åŽç›´æŽ¥ä½¿ç”¨å®ƒä»¬ã€?/p>
  当然åQŒåœ¨ä½¿ç”¨ä¹‹å‰åQŒæˆ‘们需è¦åšä¸€ä¸ªç®€å•çš„é…ç½®åQŒæŠŠä½ å°†æ¥éœ€è¦ä‹É用的¾cÕd…¨éƒ¨å‘Šè¯‰ioc容器åQŒä¾‹å¦?a target="_blank">Jdon框架的ioc容器é…ç½®jdonframework.xml如下:
<app>
  <services>
    <pojoService name="b" class="test.B"/>
    <pojoService name="a" class="test.A"/>
    <pojoService name="c" class="test.C"/>
  </services>
</app>
  注æ„åQšè™½ç„¶B¾cÖM»£ç 调用了A¾c?甚至å¯èƒ½è°ƒç”¨C½{‰å…¶ä»–ç±»)åQŒä½†æ˜¯åœ¨é…ç½®ä¸æˆ‘ä»¬æ— éœ€è€ƒè™‘˜q™ç§è°ƒç”¨å…³ç³»ã€‚å› æ¤ï¼Œæ•´ä¸ªçŽ¯èŠ‚æˆ‘ä»¬éƒ½æ— éœ€è€ƒè™‘B¾cÖM¸æ¶‰åŠå…¶ä»–¾cÈš„调用关系åQ›è¿™æ äh˜¯éžå¸¸çœæ—¶çœåŠ›çš„ï¼›ç‰¹åˆ«æ˜¯å¦‚æžœé¡¹ç›®è¾ƒå¤§ï¼ŒJavaBeansç‰¹åˆ«å¤šï¼Œåˆæ˜¯å¤šähå调开å‘,˜q™ç§æ–¹å¼å¯ÒŽé«˜å¼€å‘效率;é™ä½Žå‡ºé”™çŽ‡æ˜¯éžå¸¸å¤§çš„帮助ã€?/p>
ã€€ã€€å¦‚æžœä½ çš„™å¹ç›®ä¸æœ‰éžå¸¸å¤šçš„¾c»ï¼›è°ƒç”¨å…³ç³»å¾ˆå¤æ‚ï¼Œè€Œä¸”è°ƒç”¨å…³ç³»éšæ—¶éƒ½å¯èƒ½å˜åŒ–,那么åQŒä‹Éç”¨æ— éœ€ç…§é¡¾è°ƒç”¨å…³ç³»çš„Iocå®¹å™¨æ— ç–‘æ˜¯å‡è½Õd¼€å‘负担的首选ã€?/p>
  ioc容器å¦å¤–一个著å实现是Spring框架åQŒä½†æ˜¯åœ¨Spring的酾|®æ–‡ä»¶applicationContext.xmlä¸ï¼Œæˆ‘们必须考虑上述调用关系åQ?/p>
<bean id="b" class="test.B">
  <property name="a"><ref bean="a"/></property><!-- 必须指定调用关系 -->
  ....
</bean>
<bean id="a" class="test.A">
<bean id="c" class="test.C">
  所以,从以上对比æ¥çœ‹ï¼Œä»Žé¡¹ç›®å¼€å‘效率角度看åQŒåŸºäºŽPiocContainer实现的Jdon框架在实际ä‹É用酾|®æ•ˆçŽ‡æ— ç–‘è¦é«˜äºŽSpring框架ã€?/p>
ã€€ã€€åŒæ—¶åQŒä¹Ÿå¯ä»¥è¯ß_¼šåŸÞZºŽPiocContainer实现的Jdon框架完全真æ£å®žçŽ°äº†Ioc容器的é©å‘½æ€§ä¼˜ç‚¹ï¼šé¢ 覆了“ä‹É用对象之å‰å¿…™åÕdˆ›å»ºâ€?的基本Javaè¯è¨€å®šå¾‹
  分离å…Ïx³¨åQ?Separation of Concerns : SOCåQ‰æ˜¯Ioc模å¼å’ŒAOP产生最原始动力åQŒé€šè¿‡åŠŸèƒ½åˆ†è§£å¯å¾—到关注点åQŒè¿™äº›å…³æ³¨å¯ä»¥æ˜¯ ¾l„äšgComponents, æ–šw¢Aspects或æœåŠ¡Servicesã€?/p>
  从GoF设计模å¼ä¸ï¼Œæˆ‘们已ç»ä¹ 惯一¿Uæ€ç»´¾~–程方å¼åQšInterface Driven Design 接å£é©±åЍåQŒæŽ¥å£é©±åŠ¨æœ‰å¾ˆå¤šå¥½å¤„åQŒå¯ä»¥æä¾›ä¸åŒçµ‹zÈš„å类实现åQŒå¢žåР代ç 稳定和å¥å£®æ€§ç‰½{‰ï¼Œä½†æ˜¯æŽ¥å£ä¸€å®šæ˜¯éœ€è¦å®žçŽ°çš„åQŒä¹Ÿž®±æ˜¯å¦‚下è¯å¥˜qŸæ—©è¦æ‰§è¡Œï¼š
  AInterface a = new AInterfaceImp();
  AInterfaceImp是接å£AInterface的一个å¾c»ï¼ŒIoc模å¼å¯ä»¥å»¶ç¼“接å£çš„实玎ͼŒæ ÒŽ®éœ€è¦å®žçŽŽÍ¼Œæœ‰ä¸ªæ¯”å–»åQšæŽ¥å£å¦‚åŒç©ºçš„æ¨¡åž‹å¥—åQŒåœ¨å¿…è¦æ—Óž¼Œéœ€è¦å‘模型套注ž®„石è†ï¼Œ˜q™æ ·æ‰èƒ½æˆäØ“ä¸€ä¸ªæ¨¡åž‹å®žä½“ï¼Œå› æ¤åQŒæˆ‘们将äºÞZؓ控制接å£çš„实现æˆä¸ºâ€œæ³¨ž®„â€ã€?/p>
  Ioc英文ä¸?Inversion of ControlåQŒå³åè{模å¼åQŒè¿™é‡Œæœ‰è‘—å的好莱åžç†è®ºåQšä½ 呆ç€åˆ«åЍåQŒåˆ°æ—¶æˆ‘ä¼šæ‰¾ä½ ã€?/p>
  其实Ioc模å¼ä¹Ÿæ˜¯è§£å†³è°ƒç”¨è€…和被调用者之间的一¿Uå…³¾p»ï¼Œä¸Šè¿°AInterface实现è¯å¥è¡¨æ˜Žå½“剿˜¯åœ¨è°ƒç”¨è¢«è°ƒç”¨è€…AInterfaceImpåQŒç”±äºŽè¢«è°ƒç”¨è€…å¿U°å†™å…¥äº†è°ƒç”¨è€…的代ç ä¸ï¼Œ˜q™äñ”生了一个接å£å®žçŽ°çš„åŽŸç½ªåQšå½¼æ¤è”¾p»ï¼Œè°ƒç”¨è€…和被调用者有紧密è”ç³»åQŒåœ¨UML䏿˜¯ç”¨ä¾èµ?Dependency 表示ã€?/p>
  但是˜q™ç§ä¾èµ–在分¼›Õd…³æ³¨çš„æ€ç»´ä¸‹æ˜¯ä¸å¯å¿è€çš„åQŒå¿…™åÕdˆ‡å‰ÔŒ¼Œå®žçŽ°è°ƒç”¨è€…å’Œè¢«è°ƒç”¨è€…è§£è€¦ï¼Œæ–°çš„Iocæ¨¡å¼ Dependency Injection 模å¼ç”±æ¤äº§ç”Ÿäº†ï¼Œ Dependency Injectionæ¨¡å¼æ˜¯ä¾èµ–注ž®„çš„æ„æ€ï¼Œä¹Ÿå°±æ˜¯å°†ä¾èµ–先剥¼›»ï¼Œç„¶åŽåœ¨é€‚å½“æ—¶å€™å†æ³¨å°„˜q›å…¥ã€?/p>
Ioc模å¼åQˆDependency Injection模å¼åQ‰æœ‰ä¸‰ç§åQ?/p>
½W¬ä¸€¿Uç±»åž?/td> | 从JNDI或ServiceManager½{‰èŽ·å¾—è¢«è°ƒç”¨è€…ï¼Œ˜q™é‡Œ¾cÖM¼¼ServiceLocator模å¼ã€?/td> | 1. EJB/J2EE 2. AvalonåQˆApacheçš„ä¸€ä¸ªå¤æ‚ä‹É用ä¸å¤šçš„™å¹ç›®åQ?/td> |
½W¬äºŒ¿Uç±»åž?/td> | 使用JavaBeansçš„setteræ–ÒŽ³• | 1. Spring Framework, 2. WebWork/XWork |
½W¬ä¸‰¿Uç±»åž?/td> | åœ¨æž„é€ æ–¹æ³•ä¸å®žçްä¾èµ– | 1. PicoContainer, 2. HiveMind |
  有过EJBå¼€å‘ç»éªŒçš„人都知é“åQŒæ¯ä¸ªEJB的调用都需è¦é€šè¿‡JNDIå¯ÀL‰¾åˆ°å·¥åŽ‚æ€§è´¨çš„Home接å£åQŒåœ¨æˆ‘的教程EJB是什ä¹?/a>ç« èŠ‚ä¸ï¼Œæˆ‘也是从ä¾èµ–和工厂模å¼è§’度æ¥é˜è¿°EJBçš„ä‹É用ã€?/p>
  å‡è®¾æœ‰ä¸¤ä¸ªç±»B å’?CåQšBä½œäØ“è°ƒç”¨è€…ï¼ŒC是被调用者,在B代ç ä¸å˜åœ¨å¯¹C的调用:
public class B{ |
  实现comp实例有两¿U途径åQšå•æ€å·¥åŽ‚æ¨¡å¼å’ŒIocã€?/p>
工厂模å¼å®žçް如䏋åQ?/p>
public class B{   public B(){   } |
特点åQ?/p>
使用Iocä¾èµ–性注ž®? Dependency Injection )实现Picocontainer如下åQŒB¾cÕd¦‚åŒé€šå¸¸POJO¾c»ï¼Œå¦‚下åQ?/p>
public class B{ |
å‡è®¾C接å£/¾cÀLœ‰æœ‰ä¸€ä¸ªå…·ä½“实现CImp¾c…R€‚当客户端调用Bæ—Óž¼Œä½¿ç”¨ä¸‹åˆ—代ç åQ?/p>
public class client{ |
ã€€ã€€å› æ¤åQŒå½“客户端调用Bæ—Óž¼Œåˆ†åˆ«ä½¿ç”¨å·¥åŽ‚æ¨¡å¼å’ŒIoc有ä¸åŒçš„特点和区别:
  主è¦åŒºåˆ«ä½“现在B¾cÈš„代ç åQŒå¦‚æžœä‹É用IocåQŒåœ¨B¾cÖM»£ç 丞®†ä¸éœ€è¦åµŒå…¥ä“Q何工厂模å¼ç‰çš„代ç ï¼Œå› äØ“˜q™äº›å·¥åŽ‚æ¨¡å¼å…¶å®ž˜q˜æ˜¯ä¸ŽC有些间接的蔾p»ï¼Œ˜q™æ ·åQŒä‹É用Iocå½Õdº•解耦了Bå’ŒC之间的蔾p…R€?/p>
  使用Ioc带æ¥çš„代ä»äh˜¯åQšéœ€è¦åœ¨å®¢æˆ·ç«¯æˆ–其它æŸå¤„˜q›è¡ŒBå’ŒC之间è”系的组装ã€?/p>
  所以,Iocòq¶æ²¡æœ‰æ¶ˆé™¤Bå’ŒC之间˜q™æ ·çš„蔾p»ï¼Œåªæ˜¯è½¬ç§»äº†è¿™¿U蔾p…R€?br />  ˜q™ç§è”系转移实际也是一¿U分¼›Õd…³æ³¨ï¼Œå®ƒçš„å½±å“巨大åQŒå®ƒæä¾›äº†AOP实现的å¯èƒ½ã€?/p>
  AOP我们已ç»çŸ¥é“是一¿Ué¢å‘切é¢çš„¾~–程方å¼åQŒç”±äºŽIoc解放自由了B¾c»ï¼Œè€Œä¸”å¯ä»¥å‘B¾cÕd®žçŽ°æ³¨ž®„C¾cÕd…·ä½“实玎ͼŒå¦‚果把B¾cÀLƒ³åƒæˆ˜q行时的横å‘动作åQŒæ— 疑注入C¾cÕd¾cÕd°±æ˜¯AOPä¸çš„一¿UAdviceåQŒå¦‚下图åQ?/p>
  通过下列代ç 说明如何使用Picocontainer实现AOPåQŒè¯¥ä¾‹ç¨‹ä¸»è¦å®žçŽ°æ˜¯è®°å½•logger功能åQŒé€šè¿‡Picocontainerå¯ä»¥ä½¿ç”¨½Ž€å•一行,使所有的应用¾cÈš„记录功能‹È€‹z…R€?/p>
首先¾~–制一个记录接å£ï¼š
public interface Logging {   public void enableLogging(Log log); } |
有一个LogSwitcher¾c»ï¼Œä¸»è¦ç”¨æ¥‹È€‹zÕd…·ä½“应用ä¸çš„记录功能:
import org.apache.commons.logging.Log; public class LogSwitcher {   protected Log m_log;   public void enableLogging(Log log) {     m_log = log;     m_log.info("Logging Enabled");   } } |
一般的普通应用JavaBeans都å¯ä»¥ç‘ô承这个类åQŒå‡è®¾PicoUserManager是一个用æˆïL®¡ç†ç±»åQŒä»£ç 如下:
public class PicoUserManager extends LogSwitcher {   ..... //用户½Ž¡ç†åŠŸèƒ½   ..... //业务功能   ..... //业务功能 |
注æ„LogSwitcherä¸Log实例是由外界赋予的,也就是说å›_°†è¢«å¤–界注ž®„进入,下é¢çœ‹çœ‹ä½¿ç”¨Picocontainer是如何注ž®„Log的具体实例的ã€?/p>
Logging logging = (Logging) container.getComponentMulticaster(); |
  ç”׃¸Šä»£ç å¯è§åQŒé€šè¿‡ä½¿ç”¨½Ž€å•一行logging.enableLogging()æ–ÒŽ³•使所有的应用¾cÈš„记录功能‹È€‹z…R€‚è¿™æ˜¯ä¸æ˜¯ç±»ä¼¼AOPçš„advice实现åQ?/p>
  æ€ÖM¹‹åQŒä‹É用Ioc模å¼åQŒå¯ä»¥ä¸½Ž¡å°†æ¥å…·ä½“实玎ͼŒå®Œå…¨åœ¨ä¸€ä¸ªæŠ½è±¡å±‚‹Æ¡è¿›è¡Œæ˜q°å’ŒæŠ€æœ¯æž¶æž„ï¼Œå› æ¤åQŒIoc模å¼å¯ä»¥ä¸ºå®¹å™¨ã€æ¡†æž¶ä¹‹¾cÈš„软äšg实现æä¾›äº†å…·ä½“的实现手段åQŒå±žäºŽæž¶æž„技术ä¸ä¸€¿Ué‡è¦çš„æ¨¡å¼åº”用。Jé“çš„JdonSD框架也ä‹É用了Ioc模å¼ã€?/p>