qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          Equinox加載Bundle Class的實現(xiàn)

           Equinox在創(chuàng)建Bundle的ClassLoader時,首先獲取bundle的classpath,然后執(zhí)行createBCLPrevileged方法,此方法最后轉(zhuǎn)交由BaseData來創(chuàng)建ClassLoader。

            BaseDate創(chuàng)建ClassLoader的關(guān)鍵代碼片段為:

        1. ClassLoadingHook[] hooks = adaptor.getHookRegistry().getClassLoadingHooks(); 
        2.     ClassLoader parent = adaptor.getBundleClassLoaderParent(); 
        3.     BaseClassLoader cl = null
        4.     for (int i = 0; i < hooks.length && cl == null; i++) 
        5.        cl = hooks[i].createClassLoader(parent, delegate, domain, this, bundleclasspath); 
        6.     if (cl == null
        7.        cl = new DefaultClassLoader(parent, delegate, domain, this, bundleclasspath); 
        8.     return cl;
        9.   在Equinox中,默認的情況下adaptor.getBundleClassLoaderParent返回的為bootstrap classloader,可通過修改啟動的osgi.parentClassLoader 來改變這個parent classloader,

            osgi.parentClassLoader 的可選值有四個,分別是:

            ● boot:默認

            ● app:SystemClassLoader

            ● ext:SystemClassLoader的parent

            ● fwk:啟動Equinox的ClassLoader

            ClassLoadingHook在createClassLoader的時候都沒有做動作,因此最后ClassLoader都是通過創(chuàng)建DefaultClassLoader對象來構(gòu)建的,其中parent參數(shù)為null,delegate參數(shù)為BundleLoader實例,bundleclasspath參數(shù)為bundle的classpath。

            經(jīng)過以上步驟后,完成了ClassLoader的創(chuàng)建,可以開始加載class了,根據(jù)上面上述,Bundle的Class就由DefaultClassLoader來完成了。

            查看DefaultClassLoader的loadClass代碼,發(fā)現(xiàn)真正的加載class的過程是轉(zhuǎn)為調(diào)用了delegate 的findClass來完成的,delegate參數(shù)對應(yīng)的為BundleLoader實例,轉(zhuǎn)為跟蹤BundleLoader的findClass方法。

            BundleLoader的findClass方法的代碼片段:

        10. if (checkParent && parentCL != null && name.startsWith(JAVA_PACKAGE)) 
        11.    return parentCL.loadClass(name);
        12.   從以上這個代碼片段,可以看到,Equinox將java.開頭的類轉(zhuǎn)交給了parent classloader去加載,這也意味著沒必要在系統(tǒng)中提供對外export java.開頭的package。

            如果不是java.開頭的類,則交由findClassInternal方法來完成加載。

            findClassInternal方法遵循的為OSGi規(guī)范中定義的Class的加載順序,不過仍然稍有改動:

            1)判斷是否交由parent classloader去完成加載

            在啟動Equinox時,Equinox會讀取org.osgi.framework.bootdelegation屬性,該屬性對應(yīng)配置的為需要從parent classloader中加載的package,如值配置的為*,說明所有的都從parent classloader中加載 ,如值配置的為具體的package,那么則放入bootDelegation集合;如配置的為帶通配符的package,那么則放入bootDelegationStems集合。

            判斷時Equinox首先判斷是否所有的都從parent classloader中加載,如是則從parent classloader中加載;

            如需要加載的類的package位于bootDelegation或bootDelegationStems集合中,那么同樣從parent classloader中加載。

            如不從parent classloader中加載,則進入下面的步驟。

           2)嘗試調(diào)用Equinox提供的ClassLoaderDelegateHook的擴展來加載

            Equinox對外提供了ClassLoaderDelegateHook的接口擴展,可編寫ClassLoaderDelegateHook的實現(xiàn),注冊到Framework中,那么當有Class需要加載等動作時都會得到通知。

            在默認情況下,Equinox中沒有ClassLoaderDelegateHook的實現(xiàn),因此繼續(xù)下面的步驟。

            3)判斷是否在import-package中,如在則交由相應(yīng)的PackageSource去加載

            根據(jù)Bundle配置的import-package,判斷目前需要加載的類是否在import-package中,如在則交由對應(yīng)的PackageSource進行加載,PackageSource在加載時即直接交由對應(yīng)的Bundle的classloader去加載,如加載的類的package在import-package中,但加載后仍然沒有找到Class,則直接拋出ClassNotFoundException,如加載到,則直接返回。

            如所需要加載的類的package不在import-package中,則繼續(xù)下面的步驟。

            4)嘗試從require-bundle中加載

            嘗試使用require-bundle來加載,如加載到,則直接返回,如加載不到,則繼續(xù)下面的步驟。

            5)嘗試從當前Bundle中加載

            直到經(jīng)過以上步驟的嘗試,才嘗試由當前Bundle中加載,當前Bundle加載的方法即從Bundle-Classpath或當前Bundle的Fragment中查找相應(yīng)名稱的class文件,并讀取該文件進行加載,如class文件已加載,則進行緩存,再次加載時則不需要查找和解析class文件。

            如從當前Bundle中仍然未找到所需的類,則繼續(xù)下面的步驟。

            6)嘗試從DynamicImport-Package中加載

            判斷需要找的類的package是否在DynamicImport-Package中,如果在,則交由相應(yīng)的PackageSource進行加載,如PackageSource中加載不到,則拋出ClassNotFoundException;如不在DynamicImport-Package中,則繼續(xù)下面的步驟。

            7)再次嘗試調(diào)用Equinox提供的ClassLoaderDelegateHook的擴展來加載

            這步和第2)步相同,因此在默認情況下繼續(xù)下面的步驟。

            8)嘗試使用eclipse的buddy機制來加載

            Buddy機制是Eclipse的擴展,并不符合OSGi規(guī)范,因此在此不做深入分析。

            9)判斷一定的條件,如符合則從parent classloader中加載

            判斷的條件為:parent classloader不為null、不從parent classloader中加載、Equinox的向后兼容屬性(osgi.compatibility.bootdelegation)為true以及jvm的bug class,如滿足以上條件,則嘗試從parent classloader中加載。

            如經(jīng)過以上所有步驟后,仍然未找到需要加載的class,則拋出ClassNotFoundException。

            從上面的代碼分析中,在Equinox中可以通過osgi.parentClassLoader、org.osgi.framework.bootdelegation來控制從Bundle ClassLoader外來加載Class,這對于集成Equinox其他容器而言,非常有用,另外,還可以通過實現(xiàn)ClassLoaderDelegateHook來改變Class的加載。

          posted on 2011-11-25 17:21 順其自然EVO 閱讀(212) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          <2011年11月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 宁都县| 平乡县| 荆门市| 江城| 宁河县| 通渭县| 卫辉市| 邯郸市| 石台县| 禄劝| 浙江省| 邢台县| 玉山县| 南丹县| 仁寿县| 静宁县| 嘉义县| 台东县| 徐水县| 克东县| 鄂州市| 砚山县| 凌云县| 宜宾县| 广饶县| 林口县| 天峻县| 水富县| 安丘市| 秦皇岛市| 深水埗区| 法库县| 临夏县| 东乡县| 横山县| 绩溪县| 玛多县| 开封县| 湘阴县| 广南县| 定州市|