我正在使用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);
提前致谢!
答案 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的源代码。