将类文件的多个版本加载到JVM中
是否可以将相同类的多个版本加载到JVM中。我在主线程中加载了类“XYZ”的版本,并且我有多个子线程正在执行一些工作。我想将不同版本的类“XYZ”加载到子线程中。将类文件的多个版本加载到JVM中
这是可行的吗?我正在考虑为每个子线程创建一个新的上下文类加载器,并使用此上下文类加载器加载该类的不同版本。现在我正在使用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”中的静态字段有不同的值。
是的,这是可能的,你在URLClassLoader
正确的轨道上。您的类加载器的范围将取决于您希望static
字段具有的范围。例如,如果每个任务或线程都有自己的这些字段的副本,那么每个任务或线程都必须具有自己的类加载器。
还有一些其他问题需要注意。首先,要在系统类路径中找到要加载多次的类不得在。这是因为类加载器存在于层次结构中,并在尝试自己加载类之前将其委托给其父代。如果系统类加载器找到该类,则它只会加载一次,其他类加载器将使用由系统类加载器加载的类。其次,JVM会将每个类的加载视为一个不同的类,尽管它们都是完全相同的。这意味着动态加载类的实例必须限制在其类加载器的范围内。如果每个任务都有自己的类加载器,则不能在任务之间传递实例。显然你不能将实例发布到应用程序的其余部分,因为应用程序的其余部分使用系统类加载器,该类加载器一定不知道类。 (你可以解决这个问题有点如果动态加载的类有一个超类或超,系统类加载器不了解,然后你可以发布实例作为该类型。)
谢谢。第二个问题对我来说不是问题,因为我不打算通过实例。然而,第一个问题是一个真正的问题,并且是我正在考虑编写自定义类加载器的原因。请注意,父类加载器已经从其类路径加载了XYZ类的一个版本。我正在考虑编写一个自定义的类加载器,该类加载器在将它委托给父类加载器之前尝试加载一个类本身。我知道我需要跳过一些陷阱。例如,除了XYZ类以外,所有类都应遵循相同的类加载器层次结构。想法? – ajaymysore
@ajaymysore这可能工作。但是,这是否有一个原因必须在同一个JVM中完成?如果你有一个使用'XYZ'旧定义的辅助应用程序,你可以避免使用类加载器shenanigans。基本上是主应用程序需要的某种服务器。 –
我之所以要有不同版本的类是因为我想为类“XYZ”中的静态字段具有不同的值。
这对我来说真的很像。你真的没有其他的方法来为这个课程注入不同的价值吗?
如何为每个线程传递某种Context
实例并将您的类转换为使用Context
而不是static
字段中的设置。您也可以使用ThreadLocal
,以便每个线程都可以从中获取静态字段信息。
加载该类的不同版本将非常困难(如果不是不可能)调试。我听说过使用多个类加载器的人唯一的一次是当你有安全问题时(通常在Web服务器环境中),并且在Web类和外部管理类之间存在分离的故意点。
我认为这是一个设计问题。如果你有不同的静态字段,只要让它们不是静态的。 – TMichelsen
那么,XYZ是一个在很多地方使用的遗留类,做这种改变需要很多努力。 – ajaymysore
是否可以通过getter方法公开您的静态字段并根据调用者上下文返回不同的值?它会吸引很多重构吗? –