本文介紹了類加載器:如何加載不同版本的JAR的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我必須使用第三方平臺,但該平臺有無法替換的JARlibjar-1.0.0.jar
舊版本。該平臺允許我在其上運行我自己的(平面文件)包。我將libjar-2.0.0.jar
的新版本放在我的包/包/包名稱/外部-jar下。當我使用URLClassLoader
加載libjar-2.0.0.jar
,然后打印出所有聲明的方法時,我能夠看到2.0.0JAR中的方法。然而,當我調用時,我總是得到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);
推薦答案
類加載工作原理
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;
}
}
這篇關于類加載器:如何加載不同版本的JAR的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,