類加載器ClassLoader之jar包隔離

小引子

最近作了一個根據同一模塊的不一樣jar版本作同時測試的工具,感受挺有意思,特此記錄。html

類加載器(ClassLoader)是啥?

把類加載階段中的「經過一個類的全限定名(博主注:絕對路徑)來獲取描述此類的二進制字節流」這個動做放在Java虛擬機外部去實現,以便讓應用程序本身決定如何去獲取所須要的類。實現這個動做的代碼模塊成爲」類加載器「摘自周志明的《深刻理解Java虛擬機》java

ClassLoader的用途

  • 功能測試
    每一個加載器,有本身的獨立的類名稱空間。比較兩個類是否」相等「的前提是它們是由同一個類加載加載纔有意義,即ClassLoader若是不一樣,兩個類一定不等。這樣使得在一個JVM中加載同一個模塊的不一樣版本的jar成爲現實,基於反射功能,咱們一樣能夠很輕鬆實現不一樣版本的模塊測試。本文後面會提供簡單demo的實現。
  • 代碼加密
    沒有作過,想必是對class文件進行混淆、壓縮、native等等手段後的解密過程,這類需求還沒遇過。
  • OSGi
    是動態模型形同,在eclipse中插件的實現就是基於OSGi思想,而eclipse主要的應用就是插件,因此能夠理解爲eclipse插件是OSGi的應用典範。作的很少,僅限於瞭解。
  • 熱部署
    不中止服務,動態替換目標文件。ClassLoader動態加載jar包,若是作一個工程化的東西可能會費些周章,可是原理並不複雜。
  • ...

總之,ClassLoader很重要,Java世界須要它。eclipse

功能測試小樣

本人在本地生成了test1.jar和test2.jar兩個jar包。這兩個jar都有類com.array7.jvm.classloader.Target,此Demo要實現的是同時將這兩個jar包的同名類加載到JVM而且各自執行。
** test1.jar Target.java **jvm

package com.array7.jvm.classloader;

public class Target {
    public static void main(String[] args) {
        System.out.print("test1");
    }
}

** test2.jar Target.java **工具

package com.array7.jvm.classloader;

public class Target {
    public static void main(String[] args) {
        System.out.print("test2");
    }
}

** TestDriver**測試

public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        ClassLoader loader1 = new URLClassLoader(new URL[]{new URL("file:/home/liushijie/workspace/test/out/artifacts/test1/test1.jar")}, TestDriver.class.getClassLoader());
        ClassLoader loader2 = new URLClassLoader(new URL[]{new URL("file:/home/liushijie/workspace/test/out/artifacts/test2/test2.jar")}, TestDriver.class.getClassLoader());

        String className = "com.array7.jvm.classloader.Target";
        // loader1
        System.out.print("test1.jar \t");
        Class clazz1 = Class.forName(className, true, loader1);
        clazz1.getMethod("main", String[].class).invoke(null, (Object) null);

        System.out.println();

        // loader2
        System.out.print("test2.jar \t");
        Class clazz2 = Class.forName(className, true, loader2);
        clazz2.getMethod("main", String[].class).invoke(null, (Object) null);

        System.out.println();

        System.out.println("實例化後是否相等:" + clazz1.equals(clazz2));

    }

輸出

test1.jar   test1
test2.jar   test2
實例化後是否相等:false

其餘未提知識點

  • ClassLoader的層級關係
  • 雙親委託與打破
  • 自定義ClassLoader

其餘參考資料

相關文章
相關標籤/搜索