我必须使用第三方平台,但该平台有一个旧版本的jar libjar-1.0.0.jar
无法替换。这个平台允许我在它上面运行我自己的(平面文件)包。我将新版本的libjar-2.0.0.jar
放在我的包/ packages / package-name / external-jar下。当我使用URLClassLoader
加载libjar-2.0.0.jar
然后打印出所有声明的方法时,我能够看到2.0.0 jar中的方法。但是,当我调用时,我总是得到NoSuchMethodException
。当我打印newobj.class.getProtectionDomain().getCodeSource().getLocation().toString()
时,它始终显示libjar-1.0.0.jar
。任何人都可以帮助解释我做错了什么以及我需要做什么来强制在运行时使用特定jar中的类?
以下是我的代码的快照
File f = new File(path);
URL[] urls = new URL[1];
urls[0] = f.toURI().toURL();
ClassLoader cl = new URLClassLoader(urls);
Class<?> utilsClass = cl.loadClass("com.myclass");
Constructor<?> cons = utilsClass.getConstructor(First.class, Second.class);
Object utils = cons.newInstance(firstObj, new Second());
if (utilsClass.getProtectionDomain() != null) {
LOGGER.info(utilsClass.getProtectionDomain().getCodeSource().getLocation().toString());
}
// this print out --- 1.0.0.jar instead of 2.0.0.jar
for (Method m : utilsClass.getDeclaredMethods()) {
LOGGER.info("methods: " + m.getName());
}
// method shows the "methodILookFor"
Method m = utilsClass.getDeclaredMethod("methodILookFor", Target.class, String[].class, Object.class);
// always throws NoSuchMethodException
m.invoke(utils, target, string, obj);
答案 0 :(得分:1)
URLClassLoader
用于加载尚未在应用程序类路径中指定的类。
URLClassLoader
将类加载委托给其父级,即Application Class Loader
。 Application Class Loader
在libjar-1.0.0.jar
中找到该课程。因此,URLClassLoader
最终未加载libjar-2.0.0.jar
。这是一个扩展URLClassLoader
的自定义类加载器的简单示例。此类加载器尝试在委托其父类加载器之前从其URL加载类。它应该能够加载您的示例中所需的不同版本的JAR。您将找到一个包含单元测试的完整示例here。
P.S。 Java 9中的类加载已更改。它未使用Java 9进行测试,可能无效。
public class MyClassLoader extends URLClassLoader {
public MyClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
protected synchronized Class<?> loadClass(String name,
boolean resolve) throws ClassNotFoundException {
// 1. Check if the class has already been loaded
Class<?> clazz = findLoadedClass(name);
ClassLoader parentCL = getParent();
// 2. If the class is not loaded and the class name starts
// with 'java.' or 'javax.', delegate loading to parent
if (clazz == null && parentCL != null && (name.startsWith(
"java.") || name.startsWith(
"javax."))) {
clazz = parentCL.loadClass(name);
}
// 3. If the class is still null, try to load the class from the URL
// (since we have already taken care of 'java.' and 'javax.'
if (clazz == null) {
try {
clazz = super.findClass(name);
} catch (ClassNotFoundException e) {
//don't do anything
}
}
// 4. If the class is still null, let the parent class loader load it.
// Previously, we allowed 'java.' and 'javax.' classes to be loaded
// from parent
if (clazz == null && parentCL != null) {
clazz = parentCL.loadClass(name);
}
// 5. If the class is still null, throw a class not found exception
if (clazz == null) {
throw new ClassNotFoundException(name);
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
答案 1 :(得分:1)
您可以尝试使用自定义类加载器来使用其完全限定名称加载类,而不是使用URL类加载器。使用这种方法,你应该能够绕过类加载委托到父类加载器,这会导致你的问题。所以你的类加载器应该能够从libjar-2.0.0.jar加载类。