每个Java Class
由ClassLoader
加载。一旦加载了一个类,就不可能从类加载器中卸载这个类。 排除这一类的唯一可能性是将所有对此类加载器已加载的类的实例的所有引用全部引用到,对引用加载器本身。
类加载器按层次结构组织。默认情况下,每个类加载器首先要求其父类加载器加载一个类。只有当父类加载器无法加载类时,原始类加载器才会尝试这样做。你可以重载这个行为来加载你的JAXB类。
虽然这并不容易:假设您有一个类MyObject
,该类使用类加载器A加载。如果您使用类加载器B然后MyObject.class != MyObject.class
加载了这两个类的相同类。这也会导致MyObject o = getMyObjectFromOtherClassLoader()
抛出ClassCastException
。
Stackoverflow提供an example of a child first class loader。剩下的唯一事情就是在类加载器处于活动状态之前运行应用程序而不加载类。这一点,你可以做如下(待验证码):
class StartupWrapper {
public static void main(String[] args) throws Exception {
Class.forName("com.company.Main", true,
new ParentLastURLClassLoader(Arrays.asList(new URL("./new-JAXB.jar"))))
.getMethod("main", String[].class).invoke(null, args);
}
}
此包装将使用孩子一类加载器首先考虑您的图书馆启动类com.company.Name
你的正常应用的public static void main(String[])
方法。确保在显式加载之前不加载com.company.Main
。 (因此,反射的方法。)
您是否使用像Maven这样的构建工具?你不能明确排除旧图书馆的依赖吗?遗留应用程序可能与新应用程序在旧JAXB中存在类似的问题。
您可以使用自定义类加载器来隐藏加载的类路径,该自定义类加载器不会委托给其父类,而是尝试自行加载尽可能多的类。这样,你至少可以知道这是否是原因。 –
@raphw我比我对JVM的理解稍深。你能稍微扩展一下吗? – InfernalRapture
注释字段对于此目的有点短。请参阅下面的答案。 –