Java 使用 ClassLoader 重新加载代码时出现问题

发布于 2024-09-06 08:16:35 字数 2006 浏览 2 评论 0原文

我最近发表了一篇文章在运行时更新Java代码,经过几个小时的摆弄不同的示例代码和阅读教程我遇到了以下问题:

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

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

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

主类循环:

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

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 文件。

I recently made a post Update Java code during runtime and after a few hours fiddling around with different example codes and reading tutorials I have run into the following problem:

By using a ClassLoader I have been able to change a local variabe from Class MyVar1 to Class MyVar2 during runtime using the code at http://www.exampledepot.com/egs/java.lang/reloadclass.html, but I have been unable to replace that Class MyVar2 with another version of MyVar2.

Both MyVar1 and MyVar2 implement an interface VarInterface. The main class holds an instance of the variable using the type VarInterface.

I have read several other implementations that claim to be correct but I cannot get this to work. Can anyone see what I'm doing wrong here?

Main class loop:

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

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;
}

For the first 3 iterations MyVar1.ping() is called, after that MyVar2.ping() is called ad infinitum, even if I replace the MyVar2.class and MyVar2.java files.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

狂之美人 2024-09-13 08:16:35

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

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

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

I am guessing you are using two class loaders. One, the system class loader, with the bulk of your code in it. Your custom class loader uses the system class loader as its parent. You are trying to get the custom class loader to replace a class in the system class loader. In fact the custom class loader will delegate to the parent in preference to loading its own classes.

What you need to do is make sure that the system class loader loads no implementation of the class. Create a class loader that loads an implementation of the class and delegates to the system class loader. To change implementation create another instance of the class loader.

(Using java.net.URLClassLoader.newInstance is probably easier the creating your own class loader implementation.)

初见 2024-09-13 08:16:35

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

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

I managed to solve the problem. I forgot to keep the files out of the classpath which made the ClassLoader read a new instance only if it was of a different class implementing the same interface and not when I replaced the class with a different version.

So basically: problem solved by removing the files from the project and editing them externally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文