カスタムJAVA-JVMクラスローダー

、sun.misc.Launcher(ExtClassLoaderとAppClassLoaderを作成します)

パブリックランチャー(){ 
    Launcher.ExtClassLoader VAR1。
    試す{ 
        VAR1 = Launcher.ExtClassLoader.getExtClassLoader()。
    } キャッチ(のIOException var10){
         スロー 新しい InternalErrorを( "拡張クラスローダーを作成できませんでした" 、var10)。
    } 

    試みる{
         この .loader = Launcher.AppClassLoader.getAppClassLoader(VAR1)を、
    } キャッチ(IOExceptionをvar9){
         スロー 新しい( "アプリケーションクラスローダを作成できませんでした" InternalErrorを、var9を)。
    }

    Thread.currentThread()setContextClassLoader(。この.loader)。
    ストリングVAR2 =はSystem.getProperty( "java.security.manager" )。
    もし(!var2の= ヌル){ 
        SecurityManagerのVAR3 = nullをもし(! ""。!)VAR2(等しい&& "デフォルト" .equals(var2の)){
             しようと{ 
                VAR3 =(のSecurityManagerを)この).newInstance(.loader.loadClass(VAR2)を、
            } キャッチ(IllegalAccessExceptionがVAR5){ 
            } キャッチ(ないInstantiationException var6){ 
            }キャッチ(ClassNotFoundExceptionがvar7){ 
            } キャッチ(にClassCastExceptionがvar8){ 
            } 
        } { 
            VAR3 = 新しいセキュリティマネージャ()。
        } 

        場合(VAR3 == nullが){
             スロー 新しい InternalErrorを( "セキュリティマネージャを作成できませんでした:" + var2に)。
        } 
        System.setSecurityManager(VAR3)。
    } 
}
コードの表示

 

第二に、カスタムクラスローダ(ClassLoaderクラスの継承は、上書きにfindClassメソッド任命メカニズムを破壊するloadClassメソッドを書き換えることは推奨されません)

試験荷重クラス、の.classファイルに.javaファイルをコンパイルするjavacのを使用

パッケージコム; 

パブリック クラスこんにちは{
     静的{ 
        System.out.printlnは( "こんにちは!" ); 
    } 
    
    公共 のボイドsayHi(文字列名){ 
        System.out.printlnは( "こんにちは!" + 名)。
    } 
}

クラスローダは、パッケージ名にクラスパス名をロードするように注意を払います

パッケージコム; 

輸入java.io.ByteArrayOutputStreamを。
インポートのjava.io.File;
輸入java.io.FileInputStream;
輸入java.io.InputStreamを。
輸入java.lang.reflect.Methodオブジェクト。

パブリック クラス ClassLoaderTestが延びClassLoaderを{ 

    民間 最終 静的 filePathSuffix =「の.class」ストリングプライベート文字列filePathPrefix。

    公共ClassLoaderTest(文字列filePathPrefix){
         この .filePathPrefix = filePathPrefix。
    } 

    @Override 
    保護クラスにfindClass(文字列名)<?> { 
        文字列fileNameに = name.split( "\\。")[name.split( "\\。")長さ- 1 ]。
        バイト []バイト= loadClassDataメソッド(filePathPrefix + fileNameに+ filePathSuffix)。
        戻り defineClass(名前、バイト、0 、bytes.length)を、
    } 

    プライベート バイト[] loadClassDataメソッド(文字列filePathに){ 
        に入力ストリーム = NULL ; 
        ByteArrayOutputStreamアウト = nullを試す{  = 新しい(FileInputStreamを新しいファイル(filePathに));
            アウト= 新しいByteArrayOutputStream();
            int型私= 0 ;
            一方、(!(I = in.read())= -1 ){ 
                out.write(I)。
            } 
        } キャッチ(例外e){ 
            e.printStackTrace(); 
        } 最後に{
             試みる{ 
                out.closeを(); 
                in.close(); 
            } キャッチ(例外e){ 
                e.printStackTrace(); 
            } 
        } 
        リターン)(out.toByteArray。
    } 

    公共の 静的な 無効メイン(文字列[]引数)をスロー例外{ 
        ClassLoaderTest CLT = 新しい ClassLoaderTest( "Dを:/" )。
        クラスc = clt.loadClass( "com.Hello" )。
        System.out.println(c.getClassLoader())。
        System.out.println(c.getClassLoader()のgetParent()。)。
        System.out.println(c.getClassLoader()のgetParent()のgetParent()); 
        System.out.println(c.getClassLoader()のgetParent()のgetParent()のgetParent()。。。)。
        方法sayHi = c.getMethod( "sayHi"、文字列。クラス)。
        // 无参实例化 
        オブジェクトO = c.newInstance()。
        // 调用方法 
        sayHi.invoke(O、 "zhangsan" ); 
    } 
}

 

三、ClassLoader.loadClass和にClass.forName()()

forName0を呼び出し、2番目の引数がtrueの場合、デフォルトの初期化は、偽の使用としてのオーバーロードされたメソッドを指定することができます

@CallerSensitive
 パブリック 静的 <?>クラスにforName(文字クラス名)をスローにClassNotFoundException { 
    クラスの <?>発信者= Reflection.getCallerClass()。
    返す forName0(classNameの、真の、ClassLoader.getClassLoader(呼び出し元)、呼び出し側); 
}

オーバーロードされたメソッドはloadClassを呼び出し、デフォルトがリンクされていない、それが初期化されません。

公共 <?>クラスのloadClass(文字列名)がスローClassNotFoundExceptionが{
     返すのloadClassを(名前、); 
}

上記の例でのHelloクラス、Hello1という名前の新しいCOMパッケージで同じファイル

パブリック 静的 ボイドメイン(文字列[]引数)がスロー例外{
     // 加载、链接、初始化 
    にClass.forName( "com.Hello1" )。
    System.out.println( "==========================================" );
    // 加载、链接 
    にClass.forName( "com.Hello1"、、ClassLoader.getSystemClassLoader()); 
    System.out.println( "==========================================" );
    // 加载 
    。ClassLoader.getSystemClassLoader()はloadClass( "com.Hello1" ); 
}

 

第四に、スレッドコンテキストクラスローダ(ThreadContextClassLoader)

https://mp.weixin.qq.com/s/4FJbRLUcg8FmOqP1uz3f2A

メソッドgetContextClassLoader()とスレッドのコンテキストクラスローダを取得し、設定するsetContextClassLoader(クラスローダCL)java.lang.Threadから。

setContextClassLoader(クラスローダCL)メソッドを介して設定されていない場合、スレッドは親スレッドのコンテキストクラスローダのを継承します。

Javaのアプリケーションコンテキストクラスローダを実行する初期スレッドは、システムクラスローダです。

スレッドスレッド= 新しいスレッド(() - > {
     しようと{ 
        クラス <> AClassは=にThread.currentThread()getContextClassLoader()はloadClass( "com.Hello"?。。); 
        System.out.printlnは(aClass.getClassLoader()) ; 
    } キャッチ(ClassNotFoundExceptionが電子){ 
        e.printStackTrace(); 
    } 
})。
thread.setContextClassLoader( ClassLoaderTest( "D:/" )); 
thread.start(); 

Thread.sleep( 1000年); 

スレッド = 新しいスレッド(() - > {
     しようと{ 
        クラス<?>。AClassは=にThread.currentThread()getContextClassLoader()はloadClass( "com.Hello1" )。
        System.out.println(aClass.getClassLoader())。
    } キャッチ(ClassNotFoundExceptionが電子){ 
        e.printStackTrace(); 
    } 
})。
thread.start();


https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.3.2

https://www.cnblogs.com/editice/p/5420712.html

おすすめ

転載: www.cnblogs.com/jhxxb/p/10921945.html