将多个版本的类文件加载到JVM

时间:2016-07-26 05:39:06

标签: java multithreading classloader

是否可以将同一类的多个版本加载到JVM中。我在主线程中加载了一个类“XYZ”的版本,我有多个子线程在做一些工作。我想在子线程中加载不同版本的“XYZ”类。

这可行吗?我正在考虑为每个子线程创建一个新的上下文类加载器,并使用此上下文类加载器来加载该类的不同版本。目前我正在使用URLClassLoader作为上下文类加载器,但这似乎不起作用。我是否必须为完成工作创建自定义类加载器?

这是我到目前为止的代码。

    final Thread builderThread = new Thread("Child Thread " + buildToken) {
        @Override
        public void run() {
            futureTask.run();
        }
    };

    try {
        URL url  = new URL("file:///path to the jar file");
        URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
        classLoader.loadClass("XYZ");
        builderThread.setContextClassLoader(classLoader);
    }

我想要拥有不同版本的类的原因是因为我想为“XYZ”类中的静态字段设置不同的值。

2 个答案:

答案 0 :(得分:2)

是的,这是可能的,并且您使用URLClassLoader进入了正确的轨道。类加载器的范围将取决于您希望static字段具有的范围。例如,如果每个任务或线程都应该有自己的那些字段的副本,那么每个任务或线程都必须有自己的类加载器。

还有一些其他问题需要注意。首先,要在系统类路径中找到多次加载的类。这是因为类加载器存在于层次结构中,并且在尝试自己加载类之前委托给它们的父级。如果系统类加载器找到该类,它只加载一次,其他类加载器将使用系统类加载器加载的类。

其次,JVM会将每个类的加载视为一个独特的类,尽管它们都是相同的。这意味着动态加载的类的实例必须限制在其类加载器的范围内。如果每个任务都有自己的类加载器,则无法在任务之间传递实例。显然,您无法将实例发布到应用程序的其余部分,因为应用程序的其余部分使用系统类加载器,该类加载器必须不知道该类。 (如果动态加载的类具有系统类加载器 知道的超类或超级接口,则可以稍微解决这个问题。然后,您可以将该实例发布为该类型。)

答案 1 :(得分:0)

  

我想要拥有不同版本的类的原因是因为我想为“XYZ”类中的静态字段设置不同的值。

这对我来说真的像个黑客。你真的没有其他方法可以在这个类中注入不同的值吗?

如何为每个帖子传递某种Context个实例,并将您的类转换为使用Context而不是static字段中的设置。您也可以使用ThreadLocal,因此每个线程都会从那里获取静态字段信息。

加载不同版本的类将非常困难(如果不是不可能)进行调试。我唯一一次听说过使用多个类加载器的人就是当你遇到安全问题时(通常是在Web服务器环境中),并且有意识地将Web类和外部管理类分开。