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

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

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

    例子下載在此

    最近搞了個小實驗,發現Eclipse 插件的類加載的一個問題。Eclipse使用Equinox實現OSGi的框架,可以在插件的配置中確定哪些類expose出去,哪些類不能為外部所見。我發現的問題是,可以通過ClassLoader繞過這個限制,在外部插件中加載到插件里那些不為外部所見的類,并且能夠創建類的實例,可以通過反射調用其方法(當然,如果被加載的類實現了某些接口,也可以通過接口的引用直接調用相應的方法)。

    為了演示這個問題,先在eclipse中創建一個插件UtilityLibrary

    其中utilitylibrary.expose包中的類會暴露給外部,而utilitylibrary.hide包中的類不會暴露給外部。在MANIFEST.MF中增加這個設置:


    VisiableClassVisiableClass類的內容很簡單:
    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";
        }
    }


    其實主要就是打印出相應的信息。類代碼幾乎是一樣的。

    下面創建另一個插件UsePlugin,依賴并使用UtilityLibrary中的類。插件其實就是Eclipse自帶的Hello World程序,它會在eclipse 的toolbar上增加一個按鈕,點擊后會彈出一個MessageBox。好,MessageBox上顯示的就是從UtilityLibrary中類的方法的返回值。首先增加插件依賴關系:


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


    當然,使用VisiableClass是沒問題的。下面通過VisiableClass來將InvisiableClass拽出來,SampleAction類的源代碼如下,只要關心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");來加載本不應該被外部所見的Invisiable類。因為在Eclipse中,每個插件使用一個ClassLoader,所以用來加載VisiableClass類的ClassLoader也同樣負責加載在同一個插件中的InvisiableClass類。這樣InvisiableClass就在插件外部被加載成功了。類加載成功后,剩下的事情就是順水推舟了,創建個實例然后使用反射調用相應的方法。
    程序運行的時候,點擊toolbar上那個button,會彈出如下對話框:


    程序運行也沒啥錯誤。


    問題分析:
    其實我覺得這個問題是很難繞過去的。對于同一個插件,因為內部的類需要互相引用和互相使用,所以必須使用同一個類加載器來加載。所以,這個插件只要expose出來一個包,那么外部的插件就可以通過包中的任何一個類來得到加載這個插件中的類的類加載器,然后就可以通過reflect愛做啥做啥了。

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

    或者是我有什么地方沒設置好?求解答。例子下載在此

    Feedback

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 12:30 by Jet Geng
    你好,拜讀你的文章我發現classloader的另外一種用法。謝謝。只是有一點不太明白。你為什么要繞過osgi的這種限制。

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 12:40 by Johnny.Liang
    從設計的角度來看,通過了解一些底層機制,繞過OSGi的類加載策略來直接訪問不對外公開的類,不見得是一件好的事情,作為技術研究,了解這些底層機制有助于更熟悉一個框架,以更靈活的運用它,但作為軟件開發,這些做法可能會導致很多隱患和風險,個人認為不值得推崇。

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 12:46 by 三人行,必有我師焉
    一般隱藏起來的,都是internal的。里面的內容可以隨意改變,你用Class.ForName來初始化一個類,一旦class name改變,你的代碼就報廢了。

    這么做有什么意義呢?

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 12:57 by 深夜兩點
    @Jet Geng
    @三人行,必有我師焉
    @Johnny.Liang

    謝謝大家的關注~。 我這也只是一種嘗試,并不是在實際中要這么使用,也無意去繞過OSGi的限制,只是為了說明“可以繞過這種限制”。這么使用定然不好。所以我才覺得Equinox應該把這條路封掉。現在的疑問是Equinox沒有封掉這條路,期待的答案是Equinox能不能封掉這條路。

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 13:20 by 臨遠
    其實沒有這么麻煩,大家可以在bundle里看到有loadClass和getResource的方法,直接調用,就可以通過類名和資源名獲得對應的資源。實際上內部也是利用了classLoader。

    就像暴力反射一樣,雖然一般不會這樣用,但是也確實提供了讓你為所欲為的可能。

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 13:41 by 深夜兩點
    @臨遠
    其實沒有這么麻煩,大家可以在bundle里看到有loadClass和getResource的方法,直接調用,就可以通過類名和資源名獲得對應的資源。實際上內部也是利用了classLoader。


    請問boudle里指的是什么?

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 13:52 by 表現表達
    2010-05-17 12:40 by Johnny.Liang
    從設計的角度來看,通過了解一些底層機制,繞過OSGi的類加載策略來直接訪問不對外公開的類,不見得是一件好的事情,作為技術研究,了解這些底層機制有助于更熟悉一個框架,以更靈活的運用它,但作為軟件開發,這些做法可能會導致很多隱患和風險,個人認為不值得推崇。

    同意,真的不見得是好事情。弊大于利

    # re: OSGi(Equinox)類加載的問題——使用ClassLoader突破bundle的訪問限制  回復  更多評論   

    2010-05-17 18:03 by 臨遠
    @深夜兩點
    你看一下org.osgi.framework.Bundle的api javadoc。里邊有你需要的方法。

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


    網站導航:
     
    主站蜘蛛池模板: 三级黄色在线免费观看| 在线亚洲午夜片AV大片| 成人片黄网站色大片免费观看cn| 日本一区免费电影| 亚洲变态另类一区二区三区 | 亚洲综合一区二区精品导航| 免费久久人人爽人人爽av | 亚洲成A人片在线观看中文| 免费看一级高潮毛片| 亚洲五月午夜免费在线视频| 一级做a爰片久久毛片免费陪 | 一区国严二区亚洲三区| 少妇亚洲免费精品| 亚洲国产精品乱码一区二区 | 三级网站免费观看| 亚洲专区先锋影音| 在线视频观看免费视频18| 亚洲熟妇自偷自拍另欧美| 国产在线观看免费完整版中文版 | 亚洲精品无码久久毛片波多野吉衣| 国产免费AV片在线播放唯爱网| 亚洲熟妇无码av另类vr影视| 国产a不卡片精品免费观看| 成年女人A毛片免费视频| 亚洲精品美女视频| 美女黄网站人色视频免费国产| 一级毛片大全免费播放下载| 亚洲av无码专区国产乱码在线观看 | 99爱在线精品免费观看| 亚洲AV日韩AV永久无码色欲 | 无码视频免费一区二三区| 在线观看亚洲视频| 亚洲av永久无码精品古装片| 中文字幕av无码无卡免费| 久久www免费人成看国产片| 亚洲成A∨人片在线观看无码| 国产一级淫片a视频免费观看| 鲁丝片一区二区三区免费| 亚洲情A成黄在线观看动漫软件| 亚洲 另类 无码 在线| 久久午夜羞羞影院免费观看|