Java如何加載外部Jar的類并通過反射調(diào)用類的方法
問題
工作中遇到一個(gè)需求,客戶端將第三方的 jar 包上傳到服務(wù)器中,系統(tǒng)需要解析出上傳的 jar 中所有類以及類下的方法(方法名,方法輸入?yún)?shù)類型,方法返回值類型),并將這些類以及方法提供給配置人員選擇,由配置人員自由配置需要用到的方法。
類加載器
Java 虛擬機(jī)在加載類文件時(shí),默認(rèn)情況下使用自帶的三個(gè)類加載器
BootstrapClassLoader:加載 %JRE_HOME%\jre\lib 下的 jar 和 classExtentionClassLoader:加載 %JRE_HOME%\jre\lib\ext 下的 jar 和 classAppClassLoader:加載當(dāng)前應(yīng)用路徑下的 class
在 JDK 1.8 的 rt.jar 中,Launcher 類里定義了這三個(gè)類加載器
可以從源碼中看到,三個(gè)加載器分別指定了不同的加載路徑來加載類
BootstrapClassLoader
private static String bootClassPath = System.getProperty("sun.boot.class.path");ExtentionClassLoader
System.getProperty("java.class.path")AppClassLoader
System.getProperty("java.ext.dirs")三個(gè)加載器通過雙親委派機(jī)制來加載類文件,每個(gè)加載器都只負(fù)責(zé)加載自己負(fù)責(zé)的加載路徑,顯然,如果要自定義加載路徑,從而實(shí)現(xiàn)加載外部 jar 包,就必須自定義加載器來實(shí)現(xiàn)。
在 JDK 1.8 中,可以看到 AppClassLoader 和 ExtClassLoader 都是繼承 URLClassLoader 來實(shí)現(xiàn)的。
若要加載外部的 jar 包,只需拿到外部 jar 包的 URL 路徑,用 URLClassLoader 便可以加載。
獲取外部 jar 包中的類以及方法
public class JarUtils {
/**
* 這些默認(rèn)方法不打印
*/
private static List<String> DEFAULT_METHODS = Arrays.asList("wait", "equals", "notify", "notifyAll", "toString", "hashCode" , "getClass");
public static void parseJar(File file) throws Exception {
URL url = file.toURI().toURL();
try (URLClassLoader myClassLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader())) {
//通過jarFile和JarEntry得到所有的類
JarFile jar = new JarFile(file);
//返回zip文件條目的枚舉
Enumeration<JarEntry> enumFiles = jar.entries();
JarEntry entry;
//測(cè)試此枚舉是否包含更多的元素
while (enumFiles.hasMoreElements()) {
entry = enumFiles.nextElement();
if (entry.getName().indexOf("META-INF") < 0) {
String classFullName = entry.getName();
if (classFullName.endsWith(".class")) {
//去掉后綴.class
String className = classFullName.substring(0, classFullName.length() - 6)
.replace("/", "."); //類名
Class<?> myclass = myClassLoader.loadClass(className);
System.out.println(String.format("類名:%s", className));
//得到類中包含的屬性
Method[] methods = myclass.getMethods();
for (Method method : methods) {
String methodName = method.getName();
if (DEFAULT_METHODS.contains(methodName)) {
continue;
}
//方法名
System.out.print(String.format("方法名:%s; ", methodName));
Class<?>[] parameterTypes = method.getParameterTypes(); //方法參數(shù)類型
System.out.print(String.format("方法參數(shù)類型:%s; ", Arrays.stream(parameterTypes)
.map(Class::getSimpleName).collect(joining(","))));
System.out.println(String.format("方法返回類型:%s; ", method.getReturnType().getSimpleName())); //方法返回值類型
}
System.out.println("***************************");
}
}
}
} catch (IOException e) {
throw e;
}
}
}調(diào)用外部 jar 包中的方法
public class JarUtils {
public static void executeMethod(File f, String className, String methodName, Class[] classes, Object[] objects) {
//通過URLClassLoader加載外部jar
try (URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{f.toURI().toURL()})) {
//獲取外部jar里面的具體類對(duì)象
Class<?> targetClass = urlClassLoader.loadClass(className);
//創(chuàng)建對(duì)象實(shí)例
Object instance = targetClass.newInstance();
//獲取實(shí)例當(dāng)中的方法名為show,參數(shù)只有一個(gè)且類型為string的public方法
Method method = targetClass.getMethod(methodName, classes);
//傳入實(shí)例以及方法參數(shù)信息執(zhí)行這個(gè)方法
Object returnObj = method.invoke(instance, objects);
System.out.println(returnObj);
} catch (Exception e) {
e.printStackTrace();
}
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Java通過PropertyDescriptor反射調(diào)用set和get方法
- java反射調(diào)用方法NoSuchMethodException的解決方案
- java 反射調(diào)用Service導(dǎo)致Spring注入Dao失效的解決方案
- Java 使用反射調(diào)用jar包中的類方式
- Java使用反射調(diào)用方法示例
- java中利用反射調(diào)用另一類的private方法的簡(jiǎn)單實(shí)例
- Java 反射調(diào)用靜態(tài)方法的簡(jiǎn)單實(shí)例
- 反射調(diào)用private方法實(shí)踐(php、java)
- java反射調(diào)用get/set方法實(shí)現(xiàn)
相關(guān)文章
springboot實(shí)現(xiàn)調(diào)用百度ocr實(shí)現(xiàn)身份識(shí)別+二要素校驗(yàn)功能
本文介紹了如何使用Spring Boot調(diào)用百度OCR服務(wù)進(jìn)行身份識(shí)別,并通過二要素校驗(yàn)確保信息準(zhǔn)確性,感興趣的朋友一起看看吧2025-03-03
在mybatis 中使用if else 進(jìn)行判斷的操作
這篇文章主要介紹了在mybatis 中使用if else 進(jìn)行判斷的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(37)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
Java?Servlet異步請(qǐng)求開啟的簡(jiǎn)單步驟
Java servlet是大家公認(rèn)的服務(wù)器端web技術(shù)的標(biāo)準(zhǔn),包括jsp,jsf,和大量的web框架,soap,RESTful web service api,還有新聞供應(yīng),下面這篇文章主要給大家介紹了關(guān)于Java?Servlet異步請(qǐng)求開啟的簡(jiǎn)單步驟,需要的朋友可以參考下2022-02-02

