拾貝殼

          走過的路
          隨筆 - 39, 文章 - 1, 評(píng)論 - 14, 引用 - 0
          數(shù)據(jù)加載中……

          PicoContainer源碼導(dǎo)讀


          一、簡介
          ?? 感謝“簡易java框架”分享的學(xué)習(xí)心得。循著他的足跡,我把picocontainer讀了一遍。源代碼的版本是1.2-RC-2。
          ?? pico的官方站點(diǎn):http://www.picocontainer.org/
          ?? 由于它是一個(gè)專門的ioc容器,所以使用起來沒有spring那么麻煩。關(guān)于他的文檔,在官方站點(diǎn)上有一篇《5分鐘搞定pico》的文章。國人似乎也有很多的翻譯版本。講解得很詳細(xì),大家可以看看。
          二、快速入手
          ?? 先來體驗(yàn)一下pico的最簡單的用法。

          ???? public ? static ? void ?main(String[]?args)? {
          ????????MutablePicoContainer?pico
          = ? new ?DefaultPicoContainer( new ?SetterInjectionComponentAdapterFactory());
          ????????pico.registerComponentImplementation(User.
          class ,User. class , new ?Parameter[] { new ?ConstantParameter( new ?String

          (
          " lvhb " )), new ?ConstantParameter( new ?String( " boy " ))}
          );
          ????????pico.registerComponentInstance(String.
          class , " namea " );
          ????????
          ????????pico.registerComponentImplementation(LifeUser.
          class );
          // ????????new?VerifyingVisitor().traverse(pico);
          // ????????pico.start();
          ????????????????
          ????????LifeUser?user
          = (LifeUser)pico.getComponentInstance(LifeUser. class );
          ????????user.start();
          ?}



          ?在LifeUser的start方法中,我這樣寫到:
          ? public void start() {
          ? // TODO Auto-generated method stub
          ? System.out.println("lifeuser start");
          ? System.out.println(user.getName());
          ?}
          ?我們構(gòu)造了2個(gè)類,一個(gè)是User類,一個(gè)是LifeUser類。由于pico有管理生命周期的功能,我們把LifeUser繼承自Startable.
          ?User類有個(gè)2個(gè)屬性.name和sex.
          ?LifeUser有3個(gè)屬性.name,age和User,這里安排一個(gè)User是為了觀察它的依賴注入的過程.
          三、結(jié)構(gòu)分析
          ?下圖是PicoContainer的體系結(jié)構(gòu)。

          ?外部需要的api都有MutablePicoContainer提供.他提供了注冊(cè)/取消實(shí)現(xiàn),注冊(cè)/取消實(shí)例和設(shè)置父子關(guān)系的操作.
          ?在DefaultPicoContainer中的componentKeyToAdapterCache屬性用來存儲(chǔ)注冊(cè)過的各種類或者實(shí)例.
          ?下圖是ComponentAdapter的體系結(jié)構(gòu)

          ?ComponentAdapter是pico功能實(shí)現(xiàn)的主體.
          ?我們知道在DefaultPicoContainer我們是用一個(gè)hashmap存儲(chǔ)的key->value的鍵值對(duì)。
          ?其中的key就是我們注冊(cè)的接口,如果沒有提供接口,容器就用這個(gè)實(shí)現(xiàn)類作key.比如在上面的例子中,
          ? pico.registerComponentImplementation(LifeUser.class);我們也可以要LifeUser繼承自ILifeUser,然后寫成這樣
          ?? pico.registerComponentImplementation(ILifeUser.class,LifeUser.class);
          ?value就是我們要介紹的ComponentAdapter.

          ?在ComponentAdapter接口中,提供了5個(gè)方法,分別是:
          ?getComponentKey()獲得自己在PicoContainer里面的key
          ?getComponentImplementation()獲得自己的實(shí)現(xiàn)類
          ?getComponentInstance(PicoContainer container)生成自己的一個(gè)實(shí)例
          ?verify(PicoContainer container)檢驗(yàn)這個(gè)ComponentAdapter的依賴性是否完整。
          ?accept(PicoVisitor visitor)
          ?ComponentAdapter接口的兒孫很多,但是我們知道,流行的依賴注入目前有2中形式:構(gòu)造注入和設(shè)值注入。
          ?因此盡管實(shí)現(xiàn)或者繼承ComponentAdapter的各種類很多,最后用到的必將是2個(gè)類。
          ?SetterInjectionComponentAdapter和ConstructorInjectionComponentAdapter。有哪些中間的ComponentAdapter實(shí)現(xiàn)呢?
          ?來看看ComponentAdapter得層次:
          ?? 首先有個(gè)抽象類MonitoringComponentAdapter繼承他,在目前的版本中,monitor功能并沒有真正實(shí)現(xiàn)。
          ?? 抽象類AbstractComponentAdapter繼承自MonitoringComponentAdapter。在他的構(gòu)造函數(shù)里完成對(duì)componentKey和componentImplementation的保存。?并對(duì)componentImplementation和componentKey是否兼容作判斷。
          ?抽象類InstantiatingComponentAdapter繼承自AbstractComponentAdapter。他檢查傳入的componentImplementation是否能夠被實(shí)例化,并保存了注冊(cè)時(shí)傳入的參數(shù),是否允許沒有public構(gòu)造方法,以及生命周期策略。值得注意的是?這里聲明了一個(gè)抽象類Guard,用來在實(shí)現(xiàn)不同的注入方式時(shí)作回調(diào)函數(shù)。
          ?最終的SetterInjectionComponentAdapter和ConstructorInjectionComponentAdapter都繼承自InstantiatingComponentAdapter
          ?
          ?在ComponentAdapter的兒孫中有個(gè)CachingComponentAdapter,他繼承自DecoratingComponentAdapter,實(shí)現(xiàn)了LifecycleManager。?顧名思義,他實(shí)現(xiàn)了我們的cache.即提供單實(shí)例模式。并提供了生命周期管理的功能。
          ?這里使用了修飾模式。CachingComponentAdapter是SetterInjectionComponentAdapter和ConstructorInjectionComponentAdapter的修飾類。
          ?在這個(gè)類的內(nèi)部,額外實(shí)現(xiàn)了單實(shí)例。并對(duì)生命周期相關(guān)的過程作校驗(yàn)處理。
          ?他實(shí)現(xiàn)單實(shí)例的方法比較有意思.
          ?if (instanceReference.get() == null) {
          ??????????? Object instance = super.getComponentInstance(container);
          ??????????? instanceReference.set(instance);
          ??????? }
          四、調(diào)試跟蹤--注冊(cè)。
          ?ok,看看運(yùn)行的流程。
          ?我們先來測(cè)試默認(rèn)的用法:

          ????? public ? static ? void ?main(String[]?args)? {
          ????????MutablePicoContainer?pico
          = ? new ?DefaultPicoContainer();
          ????????pico.registerComponentImplementation(User.
          class ,User. class , new ?Parameter[] { new ?ConstantParameter( new ?String

          (
          " lvhb " )), new ?ConstantParameter( new ?String( " boy " ))}
          );
          ????????pico.registerComponentInstance(String.
          class , " namea " );
          ????????
          ????????pico.registerComponentImplementation(LifeUser.
          class );
          // ????????new?VerifyingVisitor().traverse(pico);
          ????????pico.start();
          ????????
          ????????
          ????????LifeUser?user
          = (LifeUser)pico.getComponentInstance(LifeUser. class );
          ??????
          // ??user.start();
          ?}


          ?這段代碼將輸出start里面的內(nèi)容.
          ?lifeuser start
          ? lvhb
          ? ----
          ?讓我們來debug一下上面提到的測(cè)試?yán)?
          ?1.調(diào)用DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory,LifecycleStrategy

          lifecycleStrategyForInstanceRegistrations,PicoContainer parent)
          ?? parent可以為null,其他2個(gè)如果沒有設(shè)置,將用默認(rèn)的DefaultComponentAdapterFactory和new DefaultLifecycleStrategy(new DefaultComponentMonitor()).
          ?2.注冊(cè)User類.調(diào)用registerComponentImplementation,并傳遞2各參數(shù).先調(diào)用pico初始化設(shè)置的componentAdapterFactory生成componentAdapter
          ?ComponentAdapter componentAdapter =componentAdapterFactory.createComponentAdapter(componentKey, componentImplementation, parameters).
          ?我們進(jìn)入createComponentAdapter的方法體:
          ?return new CachingComponentAdapter(new ConstructorInjectionComponentAdapter(componentKey, componentImplementation, parameters, false, currentMonitor(), lifecycleStrategy));
          ?這里的monitor和lifecycleStrategy在容器初始化componentAdapterFactory的時(shí)候已經(jīng)設(shè)置.我們?cè)谙旅娴膬?nèi)容將忽略關(guān)于監(jiān)視器和生命周期管理的內(nèi)容.
          ?這里用了ConstructorInjectionComponentAdapter,并交給CachingComponentAdapter修飾.
          ?在里面的內(nèi)容上面已經(jīng)介紹了,ConstructorInjectionComponentAdapter一級(jí)一級(jí)的向上傳遞參數(shù),一層扒一層皮.完成各種檢查.
          ?在包裝后的CachingComponentAdapter上調(diào)用registerComponent(componentAdapter),即把它加到pico的hashmap中.
          ?3.相同的原理完成String和LifeUser的注冊(cè).
          五.調(diào)試跟蹤--獲得實(shí)例

          ?1.獲得adapter.
          ??? 調(diào)用pico的getComponentInstance(Object componentKey)方法.下面是DefaultPicoContainer的方法體:
          ???

          ? public ?Object?getComponentInstance(Object?componentKey)? {
          ????????ComponentAdapter?componentAdapter?
          = ?getComponentAdapter(componentKey);
          ????????
          if ?(componentAdapter? != ? null )? {
          ????????????
          return ?getInstance(componentAdapter);
          ????????}
          ? else ? {
          ????????????
          return ? null ;
          ????????}

          ????}

          ??? getComponentAdapter(componentKey)將會(huì)在pico的hashmap中查找對(duì)應(yīng)的componentKey,如果找不到,在父容器里面找.
          ??? 獲得componentAdapter后,調(diào)用getInstance(componentAdapter);方法.因?yàn)橛锌赡苁窃诟割愔姓业降腶dapter.所以做了一定的判斷.
          ? 2.通過adapter產(chǎn)生實(shí)例
          ??? 最終調(diào)用instance = componentAdapter.getComponentInstance(this);方法.
          ??? 由于ComponentAdapter的實(shí)現(xiàn)是個(gè)ConstructorInjectionComponentAdapter,我們來看他的這個(gè)方法.
          ?? 這里有最重要的2個(gè)方法,內(nèi)部類Guard的run()和ComponentAdapter的getGreediestSatisfiableConstructor(PicoContainer container).????
          ??? 進(jìn)入getComponentInstance后,首先構(gòu)造了一個(gè)抽象類Guard的匿名內(nèi)部類給instantiationGuard,在這個(gè)類的run方法里面:
          ????? a:調(diào)用getGreediestSatisfiableConstructor方法獲得最佳的構(gòu)造函數(shù).
          ????? b:調(diào)用getConstructorArguments獲得所需的參數(shù)
          ????? c:調(diào)用newInstance(constructor, parameters)生成實(shí)例.
          ??? 我們把剛才的instantiationGuard賦上所需的參數(shù),然后調(diào)用他的observe方法.該方法:
          ??????? public final Object observe(Class stackFrame) {
          ??????? if (Boolean.TRUE.equals(get())) {
          ??????????? throw new CyclicDependencyException(stackFrame);
          ??????? }
          ??????? Object result = null;
          ??????? try {
          ??????????? set(Boolean.TRUE);
          ??????????? result = run();
          ??????? } catch (final CyclicDependencyException e) {
          ??????????? e.push(stackFrame);
          ??????????? throw e;
          ??????? } finally {
          ??????????? set(Boolean.FALSE);
          ??????? }
          ??????? return result;
          ??? }
          ??? 調(diào)用了我們?cè)O(shè)置的run()并返回結(jié)果.
          ???
          ? 六.獲得構(gòu)造函數(shù)并傳遞參數(shù)的具體過程
          ??? 這里要說的即上面獲得實(shí)例過程中run方法的實(shí)現(xiàn)細(xì)節(jié).
          ???? 1.調(diào)用getGreediestSatisfiableConstructor方法獲得最佳的構(gòu)造函數(shù).
          ???? a.首先調(diào)用getSortedMatchingConstructors方法初步篩選構(gòu)造函數(shù).
          ?

          ??? for ?( int ?i? = ? 0 ;?i? < ?allConstructors.length;?i ++ )? {
          ????????????Constructor?constructor?
          = ?allConstructors[i];
          ????????????
          if ?((parameters? == ? null ? || ?constructor.getParameterTypes().length? == ?parameters.length)? && ?(allowNonPublicClasses?

          || ?(constructor.getModifiers()? & ?Modifier.PUBLIC)? != ? 0 ))? {
          ????????????????matchingConstructors.add(constructor);
          ????????????}

          ????????}


          ? 上面這段意思是說如果注冊(cè)時(shí)沒有提供參數(shù),把所有構(gòu)造函數(shù)列為候選,如果有提供參數(shù),選取和提供參數(shù)個(gè)數(shù)相同的構(gòu)造函數(shù)作為候選.排除私有構(gòu)造函數(shù).用一個(gè)ArrayList保存所有的候選構(gòu)造函數(shù).如果注冊(cè)時(shí)候沒有配參數(shù),那么按構(gòu)造參數(shù)從多到少排列.存放在sortedMatchingConstructors中.
          ?? b.然后遍歷每一個(gè)構(gòu)造函數(shù),檢查是否是我們所需.
          ??? 我們來看這幾行代碼:
          ?????????

          ???Class[]?parameterTypes? = ?constructor.getParameterTypes();
          ????????????Parameter[]?currentParameters?
          = ?parameters? != ? null ? ? ?parameters?:?createDefaultParameters(parameterTypes);

          ????????????
          // ?remember:?all?constructors?with?less?arguments?than?the?given?parameters?are?filtered?out?already
          ???????????? for ?( int ?j? = ? 0 ;?j? < ?currentParameters.length;?j ++ )? {
          ????????????????
          // ?check?wether?this?constructor?is?statisfiable
          ???????????????? if ?(currentParameters[j].isResolvable(container,? this ,?parameterTypes[j]))? {
          ????????????????????
          continue ;
          ????????????????}

          ????????????????unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
          ????????????????unsatisfiedDependencyType?
          = ?parameterTypes[j];
          ????????????????failedDependency?
          = ? true ;
          ????????????????
          break ;
          ????????????}


          ??? c.檢查的關(guān)鍵是這段currentParameters[j].isResolvable(container, this, parameterTypes[j])
          ???? 說到這里,我們先看看他的Parameter體系
          ???????
          ??? parameters是我們?cè)谧?cè)過程中構(gòu)造componentAdapter時(shí)保存的.(User.class有參數(shù),String和LifeUser都沒有).
          ??? 從UML圖上看到,parameter有3種,我們這里著重介紹ConstantParameter和ComponentParameter
          ??? ConstantParameter用來包裝常量性質(zhì)的參數(shù),比如本文提供的例子中的參數(shù).
          ??? 來看他isResolvable方法:
          ??? 這個(gè)方法應(yīng)該是檢查注冊(cè)時(shí)的每個(gè)參數(shù)和構(gòu)造函數(shù)的每個(gè)參數(shù)是否匹配,我們進(jìn)去看看.
          ??? 他的!checkPrimitive(expectedType) && !expectedType.isInstance(value)表達(dá)式前半句對(duì)基本類型作了處理.后半句判斷注冊(cè)的參數(shù)的值是否是構(gòu)造函數(shù)對(duì)應(yīng)參數(shù)類型兼容.
          ??? ComponentParameter用來包裝組件(自定義類)類型的參數(shù).他的isResolvable和ConstantParameter是不同的.

          ??? 下面略去500字.(getTargetAdapter,? List found = container.getComponentAdaptersOfType(expectedType);)
          ???
          ??? d.如果提供的注冊(cè)參數(shù)都是構(gòu)造函數(shù)的依賴.那么failedDependency=false.我們把這個(gè)構(gòu)造函數(shù)先保存下來
          ???? greediestConstructor = constructor;
          ??? lastSatisfiableConstructorSize = parameterTypes.length;
          ????????????
          ?? 接著去檢查下一個(gè)構(gòu)造函數(shù)是否所需.
          ?? 顯然,如果注冊(cè)時(shí)設(shè)置了參數(shù),那么parameterTypes就會(huì)是個(gè)固定值,因?yàn)樵谏厦娴暮Y選中都是選擇的相同的參數(shù)個(gè)數(shù)的構(gòu)造方法.如果出現(xiàn)另外一個(gè)可以匹配的構(gòu)造函數(shù),而且參數(shù)個(gè)數(shù)相同的情況,說明存在沖突.
          ?? 我們來考慮parameters==null的情況.這個(gè)時(shí)候返回的是所有的構(gòu)造函數(shù).而且它的currentParameters =createDefaultParameters(parameterTypes).
          ?? createDefaultParameters方法是InstantiatingComponentAdapter實(shí)現(xiàn)的.代碼如下:
          ??

          ? protected ?Parameter[]?createDefaultParameters(Class[]?parameters)? {
          ????????Parameter[]?componentParameters?
          = ? new ?Parameter[parameters.length];
          ????????
          for ?( int ?i? = ? 0 ;?i? < ?parameters.length;?i ++ )? {
          ????????????componentParameters[i]?
          = ?ComponentParameter.DEFAULT;
          ????????}

          ????????
          return ?componentParameters;
          ????}


          ? 顯然,他默認(rèn)設(shè)置了ComponentParameter作為參數(shù).每個(gè)參數(shù)都是一個(gè)new ComponentParameter().參照c節(jié)介紹的判斷方法.
          如果構(gòu)造函數(shù)的每個(gè)參數(shù)都能找到依賴,(因?yàn)槭菂?shù)從大到小排列),那么它就應(yīng)該是最合適的構(gòu)造函數(shù).
          ? e.ok,我們找到了最好的構(gòu)造函數(shù)了.
          ?? 現(xiàn)在需要給這個(gè)函數(shù)找到各個(gè)參數(shù)的值.
          ???? Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
          ??? for (int i = 0; i < currentParameters.length; i++) {
          ??????????? result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i]);
          ??????? }
          ??? ConstantParameter的resolveInstance方法很簡單,就是返回parameters上對(duì)應(yīng)的值.
          ??? ComponentParameter稍顯復(fù)雜,和isResolvable類似,它需要在容器里面找到自己想要得值.先找到構(gòu)造函數(shù)參數(shù)類型的ComponentAdapter,
          然后根據(jù)adapter返回實(shí)例.在他的resolveInstance方法中這樣寫到:return container.getComponentInstance

          (componentAdapter.getComponentKey()),顯然如果有多層級(jí)聯(lián),會(huì)逐層實(shí)例下去.
          ??? 我們把找到的參數(shù)的值組成一個(gè)Object的數(shù)組.
          ? f.生成實(shí)例
          ??? 把構(gòu)造函數(shù)和參數(shù)發(fā)送給Object inst = newInstance(constructor, parameters);由newInstance返回一個(gè)實(shí)例.newInstance方法很簡單,調(diào)用jdk的方法:constructor.newInstance(parameters);
          ? g.大功告成.
          ?七.這里舉的是構(gòu)造注入的方式.設(shè)置注入在生成實(shí)例的部分和構(gòu)造注入有些區(qū)別,大體類似.
          ? 八.來看看與生命周期相關(guān)的內(nèi)容.
          ? 有生命周期的組件都能在pico注冊(cè)完成后通過調(diào)用start()方法用iterator模式逐個(gè)啟動(dòng)--即調(diào)用每個(gè)組件的start()方法.
          ? 容器先啟動(dòng)自己的所有有關(guān)的adapter, 然后去啟動(dòng)所有子類的有關(guān)adapter.
          ? 啟動(dòng)的命令是: this.lifecycleManager.start(this);
          ? 在DefaultPicoContainer里面,有個(gè)內(nèi)部類,實(shí)現(xiàn)了LifecycleManager接口.
          ? private LifecycleManager lifecycleManager = new OrderedComponentAdapterLifecycleManager();
          ? 我們來看OrderedComponentAdapterLifecycleManager的start()方法的實(shí)現(xiàn).
          ? 首先篩選有生命周期的adapter

          ? for ?( final ?Iterator?iter? = ?adapters.iterator();?iter.hasNext();)? {
          ????????????????
          final ?ComponentAdapter?adapter? = ?(ComponentAdapter)iter.next();
          ????????????????
          if ?(?adapter? instanceof ?LifecycleManager?) {
          ????????????????????LifecycleManager?manager?
          = ?(LifecycleManager)adapter;
          ????????????????????
          if ?(manager.hasLifecycle())? {
          ????????????????????????
          // ?create?an?instance,?it?will?be?added?to?the?ordered?CA?list
          ????????????????????????adapter.getComponentInstance(node);
          ????????????????????????addOrderedComponentAdapter(adapter);
          ????????????????????}

          ????????????????}

          ????????????}

          上面的意思是說.adapter必須實(shí)現(xiàn)LifecycleManager接口(通過UML圖可以看到,只有有限的幾個(gè)實(shí)現(xiàn)了他)而且實(shí)現(xiàn)類必須實(shí)現(xiàn)了startable.
          參照CachingComponentAdapter構(gòu)造函數(shù)中下面的片斷
          ?this.delegateHasLifecylce = delegate instanceof LifecycleStrategy
          ??????????????? && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
          然后對(duì)篩選出來的adapter逐個(gè)啟動(dòng)

          for ?( final ?Iterator?iter? = ?adapters.iterator();?iter.hasNext();)? {
          ????????????????
          final ?Object?adapter? = ?iter.next();
          ????????????????
          if ?(?adapter? instanceof ?LifecycleManager?) {
          ????????????????????LifecycleManager?manager?
          = ?(LifecycleManager)adapter;
          ????????????????????manager.start(node);
          ????????????????????startedComponentAdapters.add(adapter);
          ????????????????}

          ????????????}

          ?? stop()和dispose()方法則直接利用start()篩選好的adapter.
          ----end----
          ??參考文檔:
          ?????  http://dl.easyjf.com/downloads/stef_wu-PicoContainer-code.doc

          ?7/23/2006
          ?
          ?
          ?

          posted on 2006-07-23 14:30 binge 閱讀(3019) 評(píng)論(0)  編輯  收藏 所屬分類: J2EE 、OPEN SOURCE

          主站蜘蛛池模板: 密山市| 隆昌县| 黔南| 沐川县| 吕梁市| 蕉岭县| 蒲城县| 额敏县| 北海市| 开封市| 梁山县| 辛集市| 称多县| 博爱县| 通州区| 郸城县| 临城县| 时尚| 马山县| 通渭县| 承德县| 古丈县| 壤塘县| 密云县| 西乌珠穆沁旗| 揭阳市| 琼结县| 二连浩特市| 黔江区| 太保市| 杂多县| 长白| 环江| 房产| 视频| 榕江县| 龙口市| 金山区| 徐水县| 临桂县| 石台县|