23

という名前のクラスがあるとしNameGeneratorます。これを使用して、特定のロジックに従って名前を生成できます。次にTestNameGeneration、ユーザーからの手紙を要求し、それに応じて名前を生成するメソッドを含むクラスを作成します。NameGenerationここで、クラスのロジックを変更し、アプリケーションを停止せずにその特定の変更を適用したいと考えています。

クラスローダーについてもっと学ぶためにこれを行いました.

4

6 に答える 6

34

これが動作テストです。5秒ごとにTest.main()はファイルシステムからtest.Test1.classをリロードし、Test1.hello()を呼び出します

package test;

public class Test1 {
    public void hello() {
        System.out.println("Hello !");
    }
}

public class Test {

    static class TestClassLoader extends ClassLoader {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (name.equals("test.Test1")) {
                try {
                    InputStream is = Test.class.getClassLoader().getResourceAsStream("test/Test1.class");
                    byte[] buf = new byte[10000];
                    int len = is.read(buf);
                    return defineClass(name, buf, 0, len);
                } catch (IOException e) {
                    throw new ClassNotFoundException("", e);
                }
            }
            return getParent().loadClass(name);
        }
    }

    public static void main(String[] args) throws Exception {
        for (;;) {
            Class cls = new TestClassLoader().loadClass("test.Test1");
            Object obj = cls.newInstance();
            cls.getMethod("hello").invoke(obj);
            Thread.sleep(5000);
        }
    }
}

それを実行します。次に、Test1を変更して再コンパイルします

System.out.println("Hello !!!");

テストの実行中。Test1.helloの出力が変更されたことがわかります

...
Hello !
Hello !
Hello !!!
Hello !!!

これは、たとえばTomcatがWebアプリケーションをリロードする方法です。Webアプリケーションごとに個別のClassLoaderがあり、新しいClassLoaderに新しいバージョンをロードします。古いものは、他のJavaオブジェクトや古いクラスと同じようにGCされます。

TestClassLoaderを使用してTest1をロードし、リフレクションを使用して最初のメソッドを呼び出したことに注意してください。ただし、すべてのTest1依存関係は暗黙的にTest1クラスローダーでロードされます。つまり、すべてのTest1アプリケーションはJVMによってTestClassLoaderにロードされます。

于 2013-01-14T11:21:17.600 に答える
1

2 つの方法があります。

  1. 最初に既存のクラスローダーを使用してアプリケーションをブートストラップし、特に動的更新が必要なクラスを使用して、使用しているクラスローダーを上書きするには、上書きされたクラスローダーを使用する必要があります。
  2. OSGi フレームワークを使用するには。アプリケーションの規模によっては、コーディング規約に従う必要があるため、OSGi フレームワークは適切な選択ではない場合があります。

それが役に立てば幸い

于 2013-01-14T10:55:32.340 に答える
0

戦略パターンはどうですか?クラスローダーを使用する代わりに、問題のより良い解決策になる可能性があります。

于 2013-01-14T10:49:27.710 に答える
0

それは本当に簡単です.OOPの利点を利用してインターフェースを使用します.クラスローダーを管理する必要はありません.セッターで実装を注入できます.

NameGeneration というインターフェイスを作成します n 実装 NameGenerationImpl1、NameGenerationimpl2 を作成します たとえば、クライアント クラスで変数を定義します。

NameGeneration nameGeneration ;

そしてセッター:

 public void setNameGeneration(NameGeneration nameGeneration) {
 this.nameGeneration = nameGeneration ;
}

nameGeneration は、必要なものを生成します。

アルゴリズムを変更すると、たとえば次のようにして実装を変更します。

setNameGeneration(new NameGenerationImpl1()) ;

また

setNameGeneration(new NameGenerationImpl2()) ;
于 2013-01-14T10:56:10.660 に答える
0

独自のカスタム クラスローダーを作成できます。クラス ファイルまたはクラス ファイルを含むリソース/jar に変更があった場合 (タイムスタンプを確認)、以前のクラスローダー インスタンスを破棄し、新しいクラスローダー インスタンスを作成して、新しいクラス ファイルをロードします。

于 2013-01-14T14:39:15.997 に答える