<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    拾貝殼

    走過的路
    隨筆 - 39, 文章 - 1, 評論 - 14, 引用 - 0
    數據加載中……

    PicoContainer源碼導讀


    一、簡介
    ?? 感謝“簡易java框架”分享的學習心得。循著他的足跡,我把picocontainer讀了一遍。源代碼的版本是1.2-RC-2。
    ?? pico的官方站點:http://www.picocontainer.org/
    ?? 由于它是一個專門的ioc容器,所以使用起來沒有spring那么麻煩。關于他的文檔,在官方站點上有一篇《5分鐘搞定pico》的文章。國人似乎也有很多的翻譯版本。講解得很詳細,大家可以看看。
    二、快速入手
    ?? 先來體驗一下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());
    ?}
    ?我們構造了2個類,一個是User類,一個是LifeUser類。由于pico有管理生命周期的功能,我們把LifeUser繼承自Startable.
    ?User類有個2個屬性.name和sex.
    ?LifeUser有3個屬性.name,age和User,這里安排一個User是為了觀察它的依賴注入的過程.
    三、結構分析
    ?下圖是PicoContainer的體系結構。

    ?外部需要的api都有MutablePicoContainer提供.他提供了注冊/取消實現,注冊/取消實例和設置父子關系的操作.
    ?在DefaultPicoContainer中的componentKeyToAdapterCache屬性用來存儲注冊過的各種類或者實例.
    ?下圖是ComponentAdapter的體系結構

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

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

    ????? 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里面的內容.
    ?lifeuser start
    ? lvhb
    ? ----
    ?讓我們來debug一下上面提到的測試例子.
    ?1.調用DefaultPicoContainer(ComponentAdapterFactory componentAdapterFactory,LifecycleStrategy

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

    ?1.獲得adapter.
    ??? 調用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)將會在pico的hashmap中查找對應的componentKey,如果找不到,在父容器里面找.
    ??? 獲得componentAdapter后,調用getInstance(componentAdapter);方法.因為有可能是在父類中找到的adapter.所以做了一定的判斷.
    ? 2.通過adapter產生實例
    ??? 最終調用instance = componentAdapter.getComponentInstance(this);方法.
    ??? 由于ComponentAdapter的實現是個ConstructorInjectionComponentAdapter,我們來看他的這個方法.
    ?? 這里有最重要的2個方法,內部類Guard的run()和ComponentAdapter的getGreediestSatisfiableConstructor(PicoContainer container).????
    ??? 進入getComponentInstance后,首先構造了一個抽象類Guard的匿名內部類給instantiationGuard,在這個類的run方法里面:
    ????? a:調用getGreediestSatisfiableConstructor方法獲得最佳的構造函數.
    ????? b:調用getConstructorArguments獲得所需的參數
    ????? c:調用newInstance(constructor, parameters)生成實例.
    ??? 我們把剛才的instantiationGuard賦上所需的參數,然后調用他的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;
    ??? }
    ??? 調用了我們設置的run()并返回結果.
    ???
    ? 六.獲得構造函數并傳遞參數的具體過程
    ??? 這里要說的即上面獲得實例過程中run方法的實現細節.
    ???? 1.調用getGreediestSatisfiableConstructor方法獲得最佳的構造函數.
    ???? a.首先調用getSortedMatchingConstructors方法初步篩選構造函數.
    ?

    ??? 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);
    ????????????}

    ????????}


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

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

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

    ? 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;
    ????}


    ? 顯然,他默認設置了ComponentParameter作為參數.每個參數都是一個new ComponentParameter().參照c節介紹的判斷方法.
    如果構造函數的每個參數都能找到依賴,(因為是參數從大到小排列),那么它就應該是最合適的構造函數.
    ? e.ok,我們找到了最好的構造函數了.
    ?? 現在需要給這個函數找到各個參數的值.
    ???? 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上對應的值.
    ??? ComponentParameter稍顯復雜,和isResolvable類似,它需要在容器里面找到自己想要得值.先找到構造函數參數類型的ComponentAdapter,
    然后根據adapter返回實例.在他的resolveInstance方法中這樣寫到:return container.getComponentInstance

    (componentAdapter.getComponentKey()),顯然如果有多層級聯,會逐層實例下去.
    ??? 我們把找到的參數的值組成一個Object的數組.
    ? f.生成實例
    ??? 把構造函數和參數發送給Object inst = newInstance(constructor, parameters);由newInstance返回一個實例.newInstance方法很簡單,調用jdk的方法:constructor.newInstance(parameters);
    ? g.大功告成.
    ?七.這里舉的是構造注入的方式.設置注入在生成實例的部分和構造注入有些區別,大體類似.
    ? 八.來看看與生命周期相關的內容.
    ? 有生命周期的組件都能在pico注冊完成后通過調用start()方法用iterator模式逐個啟動--即調用每個組件的start()方法.
    ? 容器先啟動自己的所有有關的adapter, 然后去啟動所有子類的有關adapter.
    ? 啟動的命令是: this.lifecycleManager.start(this);
    ? 在DefaultPicoContainer里面,有個內部類,實現了LifecycleManager接口.
    ? private LifecycleManager lifecycleManager = new OrderedComponentAdapterLifecycleManager();
    ? 我們來看OrderedComponentAdapterLifecycleManager的start()方法的實現.
    ? 首先篩選有生命周期的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必須實現LifecycleManager接口(通過UML圖可以看到,只有有限的幾個實現了他)而且實現類必須實現了startable.
    參照CachingComponentAdapter構造函數中下面的片斷
    ?this.delegateHasLifecylce = delegate instanceof LifecycleStrategy
    ??????????????? && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
    然后對篩選出來的adapter逐個啟動

    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 閱讀(3017) 評論(0)  編輯  收藏 所屬分類: J2EEOPEN SOURCE

    主站蜘蛛池模板: 亚洲欧美日韩国产成人| 亚洲日韩激情无码一区| 亚洲天堂2017无码中文| 亚洲无砖砖区免费| 亚洲三级在线免费观看| 在线观看国产区亚洲一区成人| 亚洲AV无码男人的天堂| 免费观看男人免费桶女人视频| 亚洲精品无码成人| 国产大片线上免费看| 色五月五月丁香亚洲综合网| 免费一级黄色毛片| 91亚洲国产成人精品下载| 久久国产高潮流白浆免费观看| 可以免费观看一级毛片黄a| 色吊丝性永久免费看码 | 国产在线观看免费视频软件| 亚洲乱码一区二区三区在线观看 | 日韩中文无码有码免费视频| 亚洲精品色在线网站| 亚洲色偷偷狠狠综合网| 免费看男人j放进女人j免费看| 亚洲最新视频在线观看| 一级毛片大全免费播放| 久久精品国产69国产精品亚洲| 97国产在线公开免费观看| 亚洲乱码一二三四区乱码| 四虎永久在线免费观看| 久久er国产精品免费观看2| 亚洲另类小说图片| 亚洲日本在线观看视频| 日本xxxx色视频在线观看免费| 亚洲粉嫩美白在线| 爱情岛论坛网亚洲品质自拍| 99热这里有免费国产精品| 亚洲国产精品ⅴa在线观看| 亚洲av永久无码精品表情包| 成人免费视频一区| 最近2019中文免费字幕在线观看| 亚洲一区中文字幕| 亚洲精品V欧洲精品V日韩精品|