3

サーブレットでファイルをロードし、.getClassLoader().getResourceAsStream(path) を使用します。パスは WEB-INF/classes ディレクトリにあります。パス ファイルの内容を変更した後に見つけましたが、ファイル サーブレットのロードは同じです。変更しないでください。 、ファイルがキャッシュされます。

コード例:

このメソッドは、test.key コンテンツを変更した後、常に同じ結果を取得します。

private String getKey(String param){
    String name = "keys/"+param+"/test.key";
    InputStream in = XXXServlet.class.getClassLoader().getResourceAsStream(name);
    StringBuilder builder = new StringBuilder();
    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = null;
        while((line = reader.readLine()) != null){
            builder.append(line).append("\n");
        }
    } catch (IOException ignoreException) {

    }finally{
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    String result = builder.toString();
    return result;
}

================================================== ===============

これらの 2 行のコードを変更すると、正常に動作します

    String name = "/WEB-INF/classes/keys/"+param+"/test.key";
    InputStream in = getServletContext().getResourceAsStream(name);
4

2 に答える 2

0

アンクル そうですね。クラスまたはリソースを取得しようとしている既存のクラス ローダー (ファイル/入力ストリームへの名前とパスに関係なく) は、名前と関連するコンテンツがクラス ローダーまたはその親によって既に一度読み込まれている場合、再読み込みされません。これはパフォーマンス上の理由によるものです。これを行う唯一の方法は、クラス ローダーの新しいインスタンスを作成して、もう一度実行することです。ただし、少なくともクラスに関しては、互換性のないクラスがシステム内で一緒に実行されることを心配する必要があります。技術的に異なるクラスであるため、最初のクラスローダーインスタンスによってロードされたクラスで型指定された変数に、新しいクラスのインスタンスを割り当てることはできません。

Pabrantes は、Liu が「クラス」を読み込んでいるのではなく、キーを読み込んでいるため、それは違うと考えています。しかし、彼はそうするためにクラスローダーを使用しており、getResourceAsStream(name) に関して「name」をロードする際のルールは同じです。それがクラスであるかどうかは関係ありません。クラスローダは「ああ、ほら、'name' のバイト ストリームを既に読み込んでいる」と判断します。permgen からすぐに引き出します。興味のある方は、毎回リロードする独自のバージョンの新しいクラスローダーを作成/実装する場合は、非常に特定のパスまたは名前パターンに対してのみこれを行うようにしてください。また、ロードするすべてのコピーが permgen にスペースを取得する可能性が高いため、アンロードしない限り、時間の経過とともに permgen が制御不能になることに注意してください。

だから - それがうまくいかない理由です。ContextLoader は使いやすいです。:-)

ダン C.

于 2014-12-06T00:17:00.007 に答える
-1

これは、一度クラスをロードすると、再ロードしようとしても同じクラスのコンテンツが取得されるためです。これは、クラスのコンテンツが既にロードされているかどうかをチェックするためです。ロードされている場合は、再度ロードする必要はなく、(メモリ内に) すでにロードされているものを参照するだけです。

リロードを実現するには、クラスの内容 (バイト単位) を読み取り、これらのバイトを使用してクラスをロードするカスタム クラス ローダーを作成する必要があります。

サンプル CustomClassLoader コード:

public class CustomClassLoader extends ClassLoader {

private static final String CLASS_FOLDER_PATH = "/lib/all-classfiles/";
private static final String CLASS_FILE_EXTENSION = ".class";


/**
 * Loads the class file in memory
 */
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
    return findClass(className);
}

@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
    try {

        byte[] bytes = loadClassData(className);

        // Build the class based on the byte data
        return defineClass(className, bytes, 0, bytes.length);

    } catch (IOException ioException) {
        // Call super class(ClassLoader) implementation of loadClass() method
        return super.loadClass(className);
    }
}

/**
 * Returns the byte contents of the class file
 * 
 * @param className
 * @return byte[] - class file data
 * @throws IOException
 */
private byte[] loadClassData(String className) throws IOException {

    File classFile = new File(CLASS_FOLDER_PATH + className + CLASS_FILE_EXTENSION);

    int fileSize = (int) classFile.length();

    // Read the file bytes in byte array
    byte buff[] = new byte[fileSize];

    FileInputStream fis = null;
    DataInputStream dis = null;

    fis = new FileInputStream(classFile);
    dis = new DataInputStream(fis);

    // Read the byte contents of the ORM class file for loading the class
    dis.readFully(buff);

    dis.close();
    fis.close();

    return buff;
}

}

クラスのコンテンツをリロードする場合は、クラス ローダー インスタンスがガベージ コレクションされていることを確認してください。そうしないと、キャッシュされたクラス データを読み取ってしまう可能性があります。

リロード中に注意する必要があることは他にもたくさんあります。クラスのリロードに関するこの記事を読んで、詳細を理解してください。

お役に立てれば。

于 2013-03-13T09:23:40.003 に答える