2010年4月11日

          例子下載在此

          最近搞了個(gè)小實(shí)驗(yàn),發(fā)現(xiàn)Eclipse 插件的類(lèi)加載的一個(gè)問(wèn)題。Eclipse使用Equinox實(shí)現(xiàn)OSGi的框架,可以在插件的配置中確定哪些類(lèi)expose出去,哪些類(lèi)不能為外部所見(jiàn)。我發(fā)現(xiàn)的問(wèn)題是,可以通過(guò)ClassLoader繞過(guò)這個(gè)限制,在外部插件中加載到插件里那些不為外部所見(jiàn)的類(lèi),并且能夠創(chuàng)建類(lèi)的實(shí)例,可以通過(guò)反射調(diào)用其方法(當(dāng)然,如果被加載的類(lèi)實(shí)現(xiàn)了某些接口,也可以通過(guò)接口的引用直接調(diào)用相應(yīng)的方法)。

          為了演示這個(gè)問(wèn)題,先在eclipse中創(chuàng)建一個(gè)插件UtilityLibrary

          其中utilitylibrary.expose包中的類(lèi)會(huì)暴露給外部,而utilitylibrary.hide包中的類(lèi)不會(huì)暴露給外部。在MANIFEST.MF中增加這個(gè)設(shè)置:


          VisiableClassVisiableClass類(lèi)的內(nèi)容很簡(jiǎn)單:
          package utilitylibrary.expose;

          public class VisiableClass {
              
          public VisiableClass() {
                  System.out.println(
          "This is VisiableClass");
              }

              
          public String getMessage() {
                  
          return "From VisiableClass:\r\n"
                          
          + this.getClass().getClassLoader().toString() + "\t";
              }
          }

          package utilitylibrary.hide;

          public class InvisiableClass {
              
          public InvisiableClass() {
                  System.out.println(
          "InvisiableClass");
              }

              
          public String getMessage() {
                  
          return "From InvisiableClass:\r\n"
                          
          + this.getClass().getClassLoader().toString() + "\t";
              }
          }


          其實(shí)主要就是打印出相應(yīng)的信息。類(lèi)代碼幾乎是一樣的。

          下面創(chuàng)建另一個(gè)插件UsePlugin,依賴(lài)并使用UtilityLibrary中的類(lèi)。插件其實(shí)就是Eclipse自帶的Hello World程序,它會(huì)在eclipse 的toolbar上增加一個(gè)按鈕,點(diǎn)擊后會(huì)彈出一個(gè)MessageBox。好,MessageBox上顯示的就是從UtilityLibrary中類(lèi)的方法的返回值。首先增加插件依賴(lài)關(guān)系:


          在SampleAction中的Run方法里,如果直接使用InvisiableClass,插件完全找不到這個(gè)類(lèi),修改建議里面建議expose這個(gè)類(lèi):


          當(dāng)然,使用VisiableClass是沒(méi)問(wèn)題的。下面通過(guò)VisiableClass來(lái)將InvisiableClass拽出來(lái),SampleAction類(lèi)的源代碼如下,只要關(guān)心run方法就可以了:

          package useplugin.actions;

          import java.lang.reflect.InvocationTargetException;
          import java.lang.reflect.Method;

          import org.eclipse.jface.action.IAction;
          import org.eclipse.jface.dialogs.MessageDialog;
          import org.eclipse.jface.viewers.ISelection;
          import org.eclipse.ui.IWorkbenchWindow;
          import org.eclipse.ui.IWorkbenchWindowActionDelegate;

          import utilitylibrary.expose.VisiableClass;

          /**
           * Our sample action implements workbench action delegate. The action proxy will
           * be created by the workbench and shown in the UI. When the user tries to use
           * the action, this delegate will be created and execution will be delegated to
           * it.
           * 
           * 
          @see IWorkbenchWindowActionDelegate
           
          */
          public class SampleAction implements IWorkbenchWindowActionDelegate {
              
          private IWorkbenchWindow window;

              
          /**
               * The constructor.
               
          */
              
          public SampleAction() {
              }

              
          /**
               * The action has been activated. The argument of the method represents the
               * 'real' action sitting in the workbench UI.
               * 
               * 
          @see IWorkbenchWindowActionDelegate#run
               
          */
              
          public void run(IAction action) {
                  
          try {
                      Class
          <?> clazz = VisiableClass.class.getClassLoader().loadClass(
                              
          "utilitylibrary.hide.InvisiableClass");
                      Object obj 
          = clazz.newInstance();
                      Method method 
          = clazz.getMethod("getMessage");
                      Object ret 
          = method.invoke(obj, new Object[] {});
                      System.out.println(ret);
                      MessageDialog.openInformation(window.getShell(), 
          "UsePlugin", ret
                              .toString());
                  } 
          catch (ClassNotFoundException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (InstantiationException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (IllegalAccessException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (SecurityException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (NoSuchMethodException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (IllegalArgumentException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
          catch (InvocationTargetException e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  }

              }

              
          /**
               * Selection in the workbench has been changed. We can change the state of
               * the 'real' action here if we want, but this can only happen after the
               * delegate has been created.
               * 
               * 
          @see IWorkbenchWindowActionDelegate#selectionChanged
               
          */
              
          public void selectionChanged(IAction action, ISelection selection) {
              }

              
          /**
               * We can use this method to dispose of any system resources we previously
               * allocated.
               * 
               * 
          @see IWorkbenchWindowActionDelegate#dispose
               
          */
              
          public void dispose() {
              }

              
          /**
               * We will cache window object in order to be able to provide parent shell
               * for the message dialog.
               * 
               * 
          @see IWorkbenchWindowActionDelegate#init
               
          */
              
          public void init(IWorkbenchWindow window) {
                  
          this.window = window;
              }
          }


          在run方法里面,直接使用VisiableClass.class.getClassLoader().loadClass("utilitylibrary.hide.InvisiableClass");來(lái)加載本不應(yīng)該被外部所見(jiàn)的Invisiable類(lèi)。因?yàn)樵贓clipse中,每個(gè)插件使用一個(gè)ClassLoader,所以用來(lái)加載VisiableClass類(lèi)的ClassLoader也同樣負(fù)責(zé)加載在同一個(gè)插件中的InvisiableClass類(lèi)。這樣InvisiableClass就在插件外部被加載成功了。類(lèi)加載成功后,剩下的事情就是順?biāo)浦哿耍瑒?chuàng)建個(gè)實(shí)例然后使用反射調(diào)用相應(yīng)的方法。
          程序運(yùn)行的時(shí)候,點(diǎn)擊toolbar上那個(gè)button,會(huì)彈出如下對(duì)話框:


          程序運(yùn)行也沒(méi)啥錯(cuò)誤。


          問(wèn)題分析:
          其實(shí)我覺(jué)得這個(gè)問(wèn)題是很難繞過(guò)去的。對(duì)于同一個(gè)插件,因?yàn)閮?nèi)部的類(lèi)需要互相引用和互相使用,所以必須使用同一個(gè)類(lèi)加載器來(lái)加載。所以,這個(gè)插件只要expose出來(lái)一個(gè)包,那么外部的插件就可以通過(guò)包中的任何一個(gè)類(lèi)來(lái)得到加載這個(gè)插件中的類(lèi)的類(lèi)加載器,然后就可以通過(guò)reflect愛(ài)做啥做啥了。

          換一個(gè)角度可能更好理解這個(gè)問(wèn)題為什么難以繞過(guò)去。假設(shè)VisiableClass需要用到InvisiableClass,雖然InvisiableClass沒(méi)有暴露出來(lái),但是在正常的使用VisiableClass的時(shí)候,需要先加載VisiableClass類(lèi),而加載VisiableClass的時(shí)候JVM就會(huì)隱式的加載InvisiableClass。這個(gè)過(guò)程和例子里現(xiàn)式的加載InvisiableClass沒(méi)啥本質(zhì)不同。也就是說(shuō),從ClassLoader的角度,很難判斷一個(gè)類(lèi)的加載是正常的代碼還是為了突破bundle的訪問(wèn)限制——它們都是在執(zhí)行run方法時(shí)發(fā)生的類(lèi)加載行為。

          或者是我有什么地方?jīng)]設(shè)置好?求解答。例子下載在此

          posted @ 2010-05-17 12:09 深夜兩點(diǎn) 閱讀(4813) | 評(píng)論 (8)編輯 收藏

          宅能量終于爆發(fā)了,書(shū)終于出版了。China Pub有售http://www.china-pub.com/196571

          posted @ 2010-04-27 20:47 深夜兩點(diǎn) 閱讀(1676) | 評(píng)論 (1)編輯 收藏

          在設(shè)計(jì)一個(gè)多線程程序的時(shí)候,首先要考慮好線程模型是怎樣的。設(shè)計(jì)線程模型的時(shí)候可以有多個(gè)考慮,比如使用線程池,使用多個(gè)線程處理任務(wù),或者使用類(lèi)似AWT/Swing中事件處理機(jī)制那樣,使用單個(gè)線程處理同一類(lèi)的任務(wù)。

          posted @ 2010-04-26 16:33 深夜兩點(diǎn) 閱讀(252) | 評(píng)論 (0)編輯 收藏

          rt

          posted @ 2010-04-11 11:21 深夜兩點(diǎn) 閱讀(241) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 峡江县| 桑日县| 共和县| 宁陵县| 霞浦县| 嵩明县| 开原市| 蒲城县| 讷河市| 宣恩县| 沅江市| 嵩明县| 城步| 商都县| 民县| 蚌埠市| 陈巴尔虎旗| 凤山县| 柳州市| 仙居县| 河曲县| 浮梁县| 凤山市| 广安市| 剑阁县| 丰城市| 天祝| 吉水县| 华宁县| 余江县| 澄城县| 太原市| 宁国市| 正宁县| 大埔县| 长垣县| 玛纳斯县| 揭阳市| 永顺县| 名山县| 天峨县|