.getClassLoader()。getResourceAsStream(path)缓存结果

时间:2013-03-13 03:19:10

标签: java

我在servlet上加载一个文件,使用.getClassLoader()。getResourceAsStream(path),路径在WEB-INF / classes目录下,我发现我改变了路径文件内容,但文件servlet加载是一样的,不要不要改变,文件被缓存。

示例代码:

在我更改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;
}

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

更改这两行代码,工作正常

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

2 个答案:

答案 0 :(得分:0)

Ankur是对的。如果类加载器或其父级已经加载了一次名称和相关内容,则尝试获取类或资源的现有类加载器(无论文件/输入流的名称和路径如何)将永远不会重新加载。这是出于性能原因。唯一的方法是创建一个类加载器的新实例并再次执行。但是,至少在课程中,您必须担心在系统中一起运行的不兼容类。就像你不能将新类的实例分配给由第一个类加载器实例加载的类输入的变量,因为它们在技术上是不同的类。

Pabrantes认为这是不同的,因为刘没有加载一个班级'按照说,但一键:"键/" + param +" /test.key" ;;但是他使用类加载器这样做,并且在加载名称时规则相同'关于getResourceAsStream(name)。无论是否上课都没有关系,类加载器会思考"哦,你走了,我已经加载了字符串' name'"""''''''&#39 ;。将它从permgen中拉出来。对于那些感兴趣的人 - 如果您创建/实现自己的每次重新加载的类加载器版本 - 只需确保它只针对非常特定的路径或名称模式执行此操作。另外请记住,你加载的每个副本都可能在permgen中获得空间,所以随着时间的推移permgen会失去控制,除非你卸载。

那么 - 这就是为什么它不起作用。 ContextLoader很好用。 : - )

Dan C.

答案 1 :(得分:-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;
}

}

当您要重新加载类的内容时,请确保您的类加载器实例是垃圾回收的。否则你最终可能会阅读缓存的类数据。

重装时还需要处理更多事情。请阅读Class Reloading上的这篇文章,详细了解它。

希望这有帮助。