Tomcat在运行时更新java文件

时间:2018-05-27 10:27:30

标签: java eclipse tomcat servlets runtime

我正在使用servlet和JSP构建一个动态Web项目(在Eclipse中,Tomcat作为服务器)。该项目的一般目的是让用户解决小代码问题。为了做到这一点,我采用用户编写的方法并使用它来构建我可以通过 Reflection 运行的java文件。我似乎无法弄清楚的问题是Tomcat(或Eclipse?)在运行时不会更新文件。因此,当我使用当前用户的代码创建文件并尝试编译它时,我的程序总是执行文件,就像我使用前一个用户的代码启动服务器时一样。如何在运行之前告诉它更新文件?

修改 这就是我创建文件的方式:

public boolean writeFile() {
    try {
        PrintWriter writer = new PrintWriter(relativePath + "src\\testfiles\\TestFile.java");
        writer.print(content);
        writer.close();
        return true; }...

在这里,我调用编写器并尝试运行该文件:

FileWriter writer = new FileWriter(content);        
    if(writer.writeFile()){
        Class<?> TestFile;
        Method m;
        try {
            TestFile = cl.loadClass("testfiles.TestFile");
            m = TestFile.getDeclaredMethod("testSolution");
            m.invoke(null);

提前致谢!

1 个答案:

答案 0 :(得分:0)

好的,现在很清楚问题是什么。您的问题不是Tomcat没有重新加载文件,而是类加载器没有重新加载类。

普通的类加载器只会加载一次类,并永远保持缓存。类被卸载的唯一方法是通过类加载器进行垃圾回收。要重新加载一个类,你每次都必须使用不同的类加载器(前一个被垃圾收集或者你的内存不足),或者让自定义加载器thar不缓存。

有关自定义类加载器的实现,请参阅this article

理论上你每次都可以有一个新类(通过在每次保存时更改它的名称),但你最终会耗尽内存。

也许最简单的方法是在方法本身中实例化一个新的类加载器,加载一个类,在其上运行方法,并且不保留对加载器或类的任何其他引用。这样,每次都会得到一个新加载的类,并且类和加载器的旧实例都会被垃圾收集。

更新:我的假设是你已经知道如何在运行时编译一个类,但根据注释,情况并非如此。 当然,类加载器只能加载已编译的类,因此源代码不是非常有用。

Java内部提供javax.tools.JavaCompiler下的编译器接口,但它不易使用,需要在Java 9之前和之后对Java版本进行不同的处理。因此使用像{{3}这样的库要容易得多隐藏血腥的部分:

Class clazz = Reflect.compile("com.example.Test",
                "package com.example;" +
                "public class Test {\n" +
                "        public String hello() {\n" +
                "            return \"hello\";\n" +
                "        }\n" +
                "    }")
              .type();

而不是type()只是简单地获取类,你实际上可以继续使用jOOR的流畅反射API来触发生成的类上的方法或通常通过常规反射执行的任何操作。

有关直接使用JavaCompiler的信息,请参阅例如: jOOR或者更好的是,jOOR的源代码。