【问题标题】:Java problems reloading code using ClassLoader使用 ClassLoader 重新加载代码的 Java 问题
【发布时间】:2010-06-20 20:48:34
【问题描述】:

我最近发了一个帖子Update Java code during runtime,经过几个小时摆弄不同的示例代码和阅读教程后,我遇到了以下问题:

通过使用 ClassLoader,我能够在运行时使用 http://www.exampledepot.com/egs/java.lang/reloadclass.html 处的代码将本地变量从 Class MyVar1 更改为 Class MyVar2,但我无法用另一个替换该 Class MyVar2 MyVar2 的版本。

MyVar1MyVar2 都实现了一个接口 VarInterface。主类使用VarInterface 类型保存变量的实例。

我已经阅读了其他几个声称是正确的实现,但我无法让它工作。谁能看到我在这里做错了什么?

主类循环:

    while(true){  
        i++;  
        Thread.sleep(1000);  
        ui.ping();  
        if(i > 3)  
            replaceVar();  
    }

替换变量:

ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class newClass = classLoader.loadClass("MyVar2");
    ui = (VarInterface)newClass.newInstance();

MyClassLoader.loadClass:

public Class<?> loadClass(String what){
    // Get the directory (URL) of the reloadable class
    URL[] urls = null;
    try {
        // Convert the file object to a URL
        File dir = new File(System.getProperty("user.dir")
                +File.separator+"dir"+File.separator);
        URL url = dir.toURL();
        urls = new URL[]{url};
    } catch (MalformedURLException e) {
    }

    // Create a new class loader with the directory
    ClassLoader cl = new URLClassLoader(urls);

    // Load in the class
    Class cls = null;
    try {
        cls = cl.loadClass("MyVar2");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return cls;
}

对于前 3 次迭代,MyVar1.ping() 被调用,之后 MyVar2.ping() 被无限调用,即使我替换了 MyVar2.classMyVar2.java 文件。

【问题讨论】:

  • 只是为了明确这个问题 - 假设 MyVar2.ping() 打印“Hello”,当 i==10 您将课程更改为打印“再见”时,您的问题是您仍然看到“Hello”不管怎么改,对吧?
  • 那种。我没有用另一个版本(例如 i == 10)替换 MyVar2 的内部触发器,我只是直接替换文件或在 eclipse 中编辑并保存。

标签: java class classloader reloading


【解决方案1】:

我猜你正在使用两个类加载器。一,系统类加载器,其中包含大量代码。您的自定义类加载器使用系统类加载器作为其父级。您正在尝试让自定义类加载器替换系统类加载器中的类。事实上,自定义类加载器会委托给父类,而不是加载自己的类。

您需要做的是确保系统类加载器不加载该类的实现。创建一个类加载器,它加载类的实现并委托给系统类加载器。要更改实现,请创建类加载器的另一个实例。

(使用java.net.URLClassLoader.newInstance 可能更容易创建您自己的类加载器实现。)

【讨论】:

  • 我正在创建一个新的类加载器实例,正如您在上面的 replaceVar 函数中看到的那样。 “大部分代码”由循环以及 MyVar 类中的 ping() 函数组成,因为目前这只是一个沙盒实验。
【解决方案2】:

我设法解决了这个问题。我忘记将文件保留在类路径之外,这使得 ClassLoader 仅在它属于实现相同接口的不同类而不是当我用不同版本替换该类时才读取新实例。

所以基本上:通过从项目中删除文件并在外部编辑它们来解决问题。

【讨论】:

  • 如果这是解决方案,您应该自己接受它,这样很明显您的问题已经得到了回答(尽管是您自己回答的)。
猜你喜欢
  • 2018-07-05
  • 2012-10-26
  • 2012-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-22
  • 1970-01-01
相关资源
最近更新 更多