2

私の目的は、実行時に新しい属性 + getter setter メソッドをクラス定義に動的に注入することです。現在、新しく追加された属性を使用してコードを再生成し、生成されたコードをコンパイルする方法があります。

まず、コンパイル時に各クラスのテンプレートを用意します。プロジェクトを実行すると、テンプレート クラスがランタイムに読み込まれます。Javaコードを動的に生成してコンパイルするコードをいくつか書きました。以下のコードを使用して新しく作成したクラスをロードすると、注入されたメソッドにアクセスできません。既存のランタイム定義を上書きできないと思います。たくさんのブログを見てきましたが、それでも理由を理解できませんでした。助けてください。

DROOLS で新しく追加されたメソッドにアクセスしていますが、コンパイル中に問題が発生する可能性がある他のクラスでは参照されていません。新しい属性を持つルール エンジンのルールは実行時に更新されるため、それに応じてコードを調整する必要があります。以下は ClassLoader コードです。このコードは例外をスローしませんが、私の目的を解決できません。コーディングが正しいかどうかはわかりません。

public static boolean loadClass2RunTime() {
    try {
        File folder = new File("target");
        File dir = new File(folder, "com/itap/template");
        File[] classFiles = dir.listFiles();
        URL[] url = new URL[] { folder.toURI().toURL() };

        int i = 0;
        for (File classFile : classFiles) {
            if (classFile.getName().matches(".*\\.class")) {
                System.out.println(classFile.getName().substring(0,
                        classFile.getName().lastIndexOf(".")));

                ClassLoader loader = URLClassLoader
                        .newInstance(new URL[] { folder.toURI().toURL() });

                Class cls = loader.loadClass("com.itap.template."
                        + classFile.getName().substring(0,
                                classFile.getName().lastIndexOf(".")));
                ClassLoader temp = cls.getClassLoader();
            }
        }

        return true;

    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return false;
}
4

1 に答える 1

1

URLClassLoader実行時に新しく生成されたクラスをロードする必要がある場合に役立ちます。残念ながら、既にロードされているクラスの定義を再ロードする (つまり、クラスを再ロードする) ことはできませんURLCLassLoader

以下のコードを使用して新しく作成したクラスをロードすると、注入されたメソッドにアクセスできません。既存のランタイム定義を上書きできないと思います。

URLClassLoader指定されたクラスがすでにロードされているかどうかを確認します。見つかった場合は、ロードされたクラスを指すインスタンスを返すだけです。したがって、既存のランタイム定義を上書きすることはできません。

解決策: Java での動的なクラスの再読み込みをサポートする標準的な方法として、(.class ファイルから) クラスのバイト情報を読み取り、このバイト情報を使用してクラスをロードするカスタム クラス ローダーを作成する必要があります。

カスタム ClassLoader を使用する際の注意点:

  • クラスをリロードするには、(クラスをロードした) ClassLoader の既存のインスタンスと、ロードされたクラスのすべてのインスタンスをガベージ コレクションする必要があります。
  • カスタム ClassLoader では、特定のクラスのみをロードする必要があります (ロード/再ロードする必要があります)。他のすべてのクラス (ビルド内の Java クラスまたは他のパッケージのクラス) をロードする要求は、その親クラス ローダーに委譲する必要があります。組み込みのシステム クラスをロードしようとすると、特権例外が発生する場合があります。

クラスをロードするときにクラスローダーがたどる手順は次のとおりです。

  1. クラスがすでにロードされているかどうかを確認します。
  2. ロードされていない場合は、親クラス ローダーにクラスをロードするように依頼します。
  3. 親クラス ローダーがクラスをロードできない場合は、このクラス ローダーにロードしてみてください。

クラスを再ロードできるクラス・ローダーを実装する場合、このシーケンスから少し逸脱する必要があります。クラスのリロード要求は、親クラス ローダーに委任しないでください。

Java でカスタム クラス ローダーを開発するのに役立つサンプル リンクを次に示します。 http://www.javablogging.com/java-classloader-2-write-your-own-classloader/
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html

コメントの後に編集:

ステートメント InputStream stream = getClass().getClassLoader().getResourceAsStream(name); だと思います。この例の loadClassData 関数は、クラスの最新バージョンを取得していません。

そうです、ストリームを取得するために既存のものを使用しているという理由だけで、クラスの最新バージョンClassLoaderを取得していません(クラスの古いバージョンを指しています)。

むしろ、

FileInputStream stream = new FileInputStream("Path to your class file");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = stream.read();

while(data != -1){
    buffer.write(data);
    data = stream.read();
}

stream.close();

byte[] classData = buffer.toByteArray();

クラスのバイト情報を読み取り、ClassLoader(カスタム ClassLoader) のバージョンを使用してロードを試みます。

于 2014-06-16T12:20:55.610 に答える