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

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

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

    拾貝殼

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

    PicoContainer源碼導(dǎo)讀


    一、簡介
    ?? 感謝“簡易java框架”分享的學習心得。循著他的足跡,我把picocontainer讀了一遍。源代碼的版本是1.2-RC-2。
    ?? pico的官方站點:http://www.picocontainer.org/
    ?? 由于它是一個專門的ioc容器,所以使用起來沒有spring那么麻煩。關(guān)于他的文檔,在官方站點上有一篇《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());
    ?}
    ?我們構(gòu)造了2個類,一個是User類,一個是LifeUser類。由于pico有管理生命周期的功能,我們把LifeUser繼承自Startable.
    ?User類有個2個屬性.name和sex.
    ?LifeUser有3個屬性.name,age和User,這里安排一個User是為了觀察它的依賴注入的過程.
    三、結(jié)構(gòu)分析
    ?下圖是PicoContainer的體系結(jié)構(gòu)。

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

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

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

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

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

    ????????}


    ? 上面這段意思是說如果注冊時沒有提供參數(shù),把所有構(gòu)造函數(shù)列為候選,如果有提供參數(shù),選取和提供參數(shù)個數(shù)相同的構(gòu)造函數(shù)作為候選.排除私有構(gòu)造函數(shù).用一個ArrayList保存所有的候選構(gòu)造函數(shù).如果注冊時候沒有配參數(shù),那么按構(gòu)造參數(shù)從多到少排列.存放在sortedMatchingConstructors中.
    ?? b.然后遍歷每一個構(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是我們在注冊過程中構(gòu)造componentAdapter時保存的.(User.class有參數(shù),String和LifeUser都沒有).
    ??? 從UML圖上看到,parameter有3種,我們這里著重介紹ConstantParameter和ComponentParameter
    ??? ConstantParameter用來包裝常量性質(zhì)的參數(shù),比如本文提供的例子中的參數(shù).
    ??? 來看他isResolvable方法:
    ??? 這個方法應(yīng)該是檢查注冊時的每個參數(shù)和構(gòu)造函數(shù)的每個參數(shù)是否匹配,我們進去看看.
    ??? 他的!checkPrimitive(expectedType) && !expectedType.isInstance(value)表達式前半句對基本類型作了處理.后半句判斷注冊的參數(shù)的值是否是構(gòu)造函數(shù)對應(yīng)參數(shù)類型兼容.
    ??? ComponentParameter用來包裝組件(自定義類)類型的參數(shù).他的isResolvable和ConstantParameter是不同的.

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


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

    (componentAdapter.getComponentKey()),顯然如果有多層級聯(lián),會逐層實例下去.
    ??? 我們把找到的參數(shù)的值組成一個Object的數(shù)組.
    ? f.生成實例
    ??? 把構(gòu)造函數(shù)和參數(shù)發(fā)送給Object inst = newInstance(constructor, parameters);由newInstance返回一個實例.newInstance方法很簡單,調(diào)用jdk的方法:constructor.newInstance(parameters);
    ? g.大功告成.
    ?七.這里舉的是構(gòu)造注入的方式.設(shè)置注入在生成實例的部分和構(gòu)造注入有些區(qū)別,大體類似.
    ? 八.來看看與生命周期相關(guān)的內(nèi)容.
    ? 有生命周期的組件都能在pico注冊完成后通過調(diào)用start()方法用iterator模式逐個啟動--即調(diào)用每個組件的start()方法.
    ? 容器先啟動自己的所有有關(guān)的adapter, 然后去啟動所有子類的有關(guān)adapter.
    ? 啟動的命令是: this.lifecycleManager.start(this);
    ? 在DefaultPicoContainer里面,有個內(nèi)部類,實現(xiàn)了LifecycleManager接口.
    ? private LifecycleManager lifecycleManager = new OrderedComponentAdapterLifecycleManager();
    ? 我們來看OrderedComponentAdapterLifecycleManager的start()方法的實現(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必須實現(xiàn)LifecycleManager接口(通過UML圖可以看到,只有有限的幾個實現(xiàn)了他)而且實現(xiàn)類必須實現(xiàn)了startable.
    參照CachingComponentAdapter構(gòu)造函數(shù)中下面的片斷
    ?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 閱讀(3016) 評論(0)  編輯  收藏 所屬分類: J2EE 、OPEN SOURCE

    主站蜘蛛池模板: 成人a毛片视频免费看| 欧美亚洲精品一区二区| 亚洲小说区图片区| 自拍偷区亚洲国内自拍| 小说专区亚洲春色校园| 久久久精品视频免费观看 | 亚洲AV中文无码乱人伦在线视色| 亚洲国产一成久久精品国产成人综合| 亚洲综合色婷婷七月丁香| 亚洲福利在线视频| 日韩亚洲国产综合高清| 一级特黄aaa大片免费看| 午夜不卡久久精品无码免费| 国产成人无码免费看视频软件| 免费看国产精品麻豆| 久久精品国产亚洲沈樵| 亚洲日韩国产精品乱-久| 国产午夜亚洲精品不卡免下载 | 99ee6热久久免费精品6| 成年人视频在线观看免费 | 免费无码一区二区三区蜜桃大| 亚洲高清偷拍一区二区三区| 久热综合在线亚洲精品| 亚洲码和欧洲码一码二码三码| 免费无码国产在线观国内自拍中文字幕 | 国产亚洲综合成人91精品| 亚洲免费观看网站| 成人免费观看男女羞羞视频| 18成禁人视频免费网站| 四虎永久在线精品免费影视 | 国产成人99久久亚洲综合精品| 亚洲小视频在线观看| 国产精品国产亚洲区艳妇糸列短篇| 丁香花在线视频观看免费| 好爽…又高潮了免费毛片| 亚洲精品你懂的在线观看| 国产亚洲精品影视在线| 叮咚影视在线观看免费完整版| 成人性生交大片免费看午夜a| 亚洲国产精品高清久久久| 激情小说亚洲色图|