Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【Eclipse插件開發(fā)】Eclipse插件Lazy Start實現(xiàn)原理分析

                   

          Eclipse插件Lazy Start實現(xiàn)原理分析

                                                                                              朱興zhu_xing@live.cn

                 每次提到有關(guān)Eclipse插件啟動的問題的時候,腦子中自然的反應(yīng)就是:可以設(shè)定為預(yù)先啟動(org.eclipse.ui.startup),否則默認(rèn)的情況下是懶啟動(Lazy Start),只有當(dāng)插件中的功能被真正調(diào)用的時候,插件才會被啟動??赡苁侨艘哺儜辛?,也一直沒有去留心Eclipse底層是怎么實現(xiàn)這種懶加載的,只是有個大致的猜測,估計又是用hook機(jī)制了。昨天閑著具體看了一下實現(xiàn),果然是類似的實現(xiàn)。下面就大致和大家分享一下,說的不一定準(zhǔn)確,僅供參考 _~。

                 直接進(jìn)入主題,我們的Eclipse實例啟動肯定要構(gòu)造工作區(qū),那么ResourcesPlugin肯定會被啟動,我們就在ResourcesPlugin.startup方法設(shè)置一個斷點,調(diào)試棧如下:
              
              

                   

              假設(shè)我們對插件類型加載細(xì)節(jié)不知道,猜測大致過程如下:

                  1、 DefaultClassLoader加載類型(org.eclipse.core.resources.IContainer

                  2、EclipseLazyStarter.preFindLocalClass

                  3、 啟動資源插件:ResourcesPlugin.startup

                   

              補(bǔ)充說明:

                  1、 org.eclipse.osgi.internal.baseadaptor.DefaultClassLoaderEclipse針對OSGI類加載實現(xiàn)的核心角色,也是eclipse插件默認(rèn)的類加載器類型,當(dāng)然,每個插件有自己獨立的類加載器實例來負(fù)責(zé)類型加載。

                  2、 DefaultClassLoader、BundleLoaderClasspathManager三者協(xié)作,處理類型加載請求(為什么一個類加載過程要搞的這么復(fù)雜呢?Eclipse的考慮是什么呢? 大家思考吧~_~)

              
                  【EclipseLazyStarter調(diào)用分析】
                  我們先大致看一下EclipseLazyStarter.preFindLocalClass方法的代碼實現(xiàn)

          1 public class EclipseLazyStarter implements ClassLoadingStatsHook, HookConfigurator {
          2     public void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException {
          3         //首先判斷,如果不需要啟動則返回
          4          
          5          //如果插件正在啟動,則設(shè)定5000ms超時等待;如果超時,直接報錯返回
          6 
          7          //啟動插件
          8     }
          9 }
                 

              加載類型之前為什么要給回調(diào)一下EclipseLazyStarter. preFindLocalClass,又hook了?我們看了一下EclipseLazyStarter繼承了ClassLoadingStatsHook接口,ClassLoadingStatsHook接口的類型API文檔說明了它的作用:

          A ClassLoadingStatsHook hooks into the <code>ClasspathManager</code> class.


                  追蹤前面的調(diào)用棧,ClassLoadingStatsHook是在ClasspathManager.findLocalClass中被調(diào)用的:
                  
           1 public Class findLocalClass(String classname) throws ClassNotFoundException {
           2         Class result = null;
           3         ClassLoadingStatsHook[] hooks = data.getAdaptor().getHookRegistry().getClassLoadingStatsHooks();
           4         try {
           5             for (int i = 0; i < hooks.length; i++)
           6                 hooks[i].preFindLocalClass(classname, this);
           7             result = findLocalClassImpl(classname, hooks);
           8             return result;
           9         } finally {
          10             for (int i = 0; i < hooks.length; i++)
          11                 hooks[i].postFindLocalClass(classname, result, this);
          12         }
          13     }

                  再接著往下看之前,我們大致已經(jīng)知道來的Eclipse的插件lazy start是怎么回事了:
                  EclipseLazyStarter hook到了插件類加載器的類型加載過程中了,在類型被加載之前會回調(diào)EclipseLazyStarter. preFindLocalClass方法:如果類型所在插件還沒啟動,啟動它;如果正在啟動,則設(shè)置5000ms的超時,限時不能完成啟動,則報錯返回!

             (附加說明:頭一段時間在另外一篇隨筆中,寫了一些編寫插件啟動類應(yīng)該注意的點,其中有一條就是避免在插件啟動方法中干耗時的事情。這里真正告訴我們了原因:如果超過5000ms不能完成啟動--注意這其中還不包含所依賴插件的啟動時間,那么肯定會出現(xiàn)類加載超時的錯誤了:
               While loading class "{1}", thread "{0}" timed out waiting ({4}ms) for thread "{2}" to finish starting bundle "{3}". To avoid deadlock, thread "{0}" is proceeding but "{1}" may not be fully initialized.
              )

              【EclipseLazyStarter是如何完成注冊過程的?】
              
              過程簡要解釋如下:
              1、啟動osgi framework,兩種啟動方式:如果想利用Eclipse的一些特性,則就以EclipseStarter為入口點啟動;否則,可以用命令行的方式,以Laucher.main為入口點啟動
              2、初始化FrameworkAdaptor(對應(yīng)eclipse實現(xiàn)是BaseAdaptor)看一下接口說明:
                  
          /**
           * FrameworkAdaptor interface to the osgi framework. This class is used to provide
           * platform specific support for the osgi framework.
           *
           * <p>The OSGi framework will call this class to perform platform specific functions.
           *
           * Classes that implement FrameworkAdaptor MUST provide a constructor that takes as a
           * parameter an array of Strings.  This array will contain arguments to be
           * handled by the FrameworkAdaptor.  The FrameworkAdaptor implementation may define the format
           * and content of its arguments.
           *
           * The constructor should parse the arguments passed to it and remember them.
           * The initialize method should perform the actual processing of the adaptor
           * arguments.
           * <p>
           * Clients may implement this interface.
           * </p>
           * 
          @since 3.1
           
          */
                顯而易見,F(xiàn)rameworkAdaptor其實是osgi framework的后門,提供平臺附加支持。
                 
                看一下BaseAdaptor的構(gòu)造函數(shù):
                
           1 /**
           2      * Constructs a BaseAdaptor.
           3      * @param args arguments passed to the adaptor by the framework.
           4      */
           5     public BaseAdaptor(String[] args) {
           6         if (LocationManager.getConfigurationLocation() == null)
           7             LocationManager.initializeLocations();
           8         hookRegistry = new HookRegistry(this);
           9         FrameworkLogEntry[] errors = hookRegistry.initialize();
          10         if (errors.length > 0)
          11             for (int i = 0; i < errors.length; i++)
          12                 getFrameworkLog().log(errors[i]);
          13         // get the storage after the registry has been initialized
          14         storage = getStorage();
          15         // TODO consider passing args to BaseAdaptorHooks
          16     }
                我們看到,調(diào)用了HookRegistry.initialize進(jìn)行初始化
                  
              3、初始化HookRegistry,我們直接看一下HookRegistry.initialize方法實現(xiàn)
                  
           1 /**
           2      * Initializes the hook configurators.  The following steps are used to initialize the hook configurators. <p>
           3      * 1. Get a list of hook configurators from all hook configurators properties files on the classpath, 
           4      *    add this list to the overall list of hook configurators, remove duplicates. <p>
           5      * 2. Get a list of hook configurators from the (&quot;osgi.hook.configurators.include&quot;) system property 
           6      *    and add this list to the overall list of hook configurators, remove duplicates. <p>
           7      * 3. Get a list of hook configurators from the (&quot;osgi.hook.configurators.exclude&quot;) system property
           8      *    and remove this list from the overall list of hook configurators. <p>
           9      * 4. Load each hook configurator class, create a new instance, then call the {@link HookConfigurator#addHooks(HookRegistry)} method <p>
          10      * 5. Set this HookRegistry object to read only to prevent any other hooks from being added. <p>
          11      * @return an array of error log entries that occurred while initializing the hooks
          12      */
          13     public FrameworkLogEntry[] initialize() {
          14         ArrayList configurators = new ArrayList(5);
          15         ArrayList errors = new ArrayList(0); // optimistic that no errors will occur
          16         mergeFileHookConfigurators(configurators, errors);
          17         mergePropertyHookConfigurators(configurators);
          18         loadConfigurators(configurators, errors);
          19         // set to read-only
          20         readonly = true;
          21         return (FrameworkLogEntry[]) errors.toArray(new FrameworkLogEntry[errors.size()]);
          22     }

                其中的mergeFileHookConfigurators方法調(diào)用,讀取了一個名為hookconfigurators.properties的屬性配置文件,在org.eclipse.osgi插件中??匆幌吕锩娴膬?nèi)容:
               
           1 ###############################################################################
           2 # Copyright (c) 20052006 IBM Corporation and others.
           3 # All rights reserved. This program and the accompanying materials
           4 # are made available under the terms of the Eclipse Public License v1.0
           5 # which accompanies this distribution, and is available at
           6 # http://www.eclipse.org/legal/epl-v10.html
           7 #
           8 # Contributors:
           9 #     IBM Corporation - initial API and implementation
          10 ###############################################################################
          11 hook.configurators= \
          12  org.eclipse.osgi.internal.baseadaptor.BaseHookConfigurator,\
          13  org.eclipse.osgi.internal.baseadaptor.DevClassLoadingHook,\
          14  org.eclipse.core.runtime.internal.adaptor.EclipseStorageHook,\
          15  org.eclipse.core.runtime.internal.adaptor.EclipseLogHook,\
          16  org.eclipse.core.runtime.internal.adaptor.EclipseErrorHandler,\
          17  org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorHook,\
          18  org.eclipse.core.runtime.internal.adaptor.EclipseClassLoadingHook,\
          19  org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter,\
          20  org.eclipse.core.runtime.internal.stats.StatsManager,\
          21  org.eclipse.osgi.internal.verifier.SignedBundleHook
          22 


              ^_^,我們的EclipseLazyStarter赫然在列!??!

               
              回過頭來看一下EclipseLazyStarter(繼承ClassLoadingStatsHook)的使用方式:
              BaseAdaptor.getHookRegistry().getClassLoadingStatsHooks()

              前面已經(jīng)看了ClasspathManager中findLocalClass方法的代碼,就是這么調(diào)用ClassLoadingStatsHook policy的(我們的EclipseLazyStarter...)

             【總結(jié)】
              hook了,osgi framework留了個后門,Eclipse好好的利用了這個后門~_~

             【附加說明】
              1、EclipseLazyStarter只是ClassLoadingStatsHook policy的實現(xiàn),其實HookRegsitry中還有其他的hook policy,例如:
              org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook
              org.eclipse.osgi.baseadaptor.hooks.BundleFileWrapperFactoryHook
              org.eclipse.osgi.baseadaptor.hooks.BundleFileFactoryHook
              org.eclipse.osgi.baseadaptor.hooks.StorageHook
              org.eclipse.osgi.baseadaptor.hooks.AdaptorHook

              2、大家可以順帶詳細(xì)的看一下HookRegistry、HookConfigurator、BaseAdaptor等

              3、hook這種手法在Eclipse的資源管理中也有比較成功的應(yīng)用,可以看一下
              org.eclipse.core.resources.team.IMoveDeleteHook
              例如cvs、ClearCase等團(tuán)隊開發(fā)管理工具中,都實現(xiàn)了這種hook,通過擴(kuò)展點org.eclipse.core.resources.moveDeleteHook動態(tài)掛入。大家有興趣可以深入看看,看過之后應(yīng)該就明白了為什么cvs、ClearCase等一些團(tuán)隊開發(fā)管理工具功能有一些不同了~_~
              
              4、對osgi感興趣的同學(xué),可以看一下org.eclipse.osgi插件中的代碼,質(zhì)量很高~_~
              亂轟轟的,湊合著看吧



          本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!

          posted on 2008-08-19 18:05 zhuxing 閱讀(2667) 評論(2)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGI

          評論

          # re: 【Eclipse插件開發(fā)】Eclipse插件Lazy Start實現(xiàn)原理分析  回復(fù)  更多評論   

          老弟,寫的通俗易懂一點好不好,看得比較暈:)

          鼓勵一下,很有鉆研精神!
          2008-08-20 21:23 | Always BaNg.

          # re: 【Eclipse插件開發(fā)】Eclipse插件Lazy Start實現(xiàn)原理分析  回復(fù)  更多評論   

          比較高深,迷茫中。。。。。。
          2008-12-06 09:58 | 楓葉KR
          主站蜘蛛池模板: 甘孜| 通化市| 寻甸| 南和县| 南宁市| 武穴市| 三原县| 蒲江县| 宁海县| 类乌齐县| 孙吴县| 长治市| 竹山县| 石柱| 黄石市| 乌苏市| 宁武县| 香河县| 永新县| 鄱阳县| 凌海市| 清水河县| 林甸县| 朝阳市| 吴忠市| 松潘县| 丰城市| 连南| 渭源县| 田阳县| 苍溪县| 宁德市| 卓尼县| 双辽市| 奇台县| 将乐县| 云安县| 资阳市| 文山县| 革吉县| 清水河县|