Java如何加載外部Jar的類并通過(guò)反射調(diào)用類的方法
問(wèn)題
工作中遇到一個(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è)加載器分別指定了不同的加載路徑來(lái)加載類
BootstrapClassLoader
private static String bootClassPath = System.getProperty("sun.boot.class.path");
ExtentionClassLoader
System.getProperty("java.class.path")
AppClassLoader
System.getProperty("java.ext.dirs")
三個(gè)加載器通過(guò)雙親委派機(jī)制來(lái)加載類文件,每個(gè)加載器都只負(fù)責(zé)加載自己負(fù)責(zé)的加載路徑,顯然,如果要自定義加載路徑,從而實(shí)現(xiàn)加載外部 jar 包,就必須自定義加載器來(lái)實(shí)現(xiàn)。
在 JDK 1.8 中,可以看到 AppClassLoader 和 ExtClassLoader 都是繼承 URLClassLoader 來(lái)實(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())) { //通過(guò)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) { //通過(guò)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è)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Maven實(shí)現(xiàn)項(xiàng)目構(gòu)建工具
本文主要介紹了Maven實(shí)現(xiàn)項(xiàng)目構(gòu)建工具,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例
這篇文章主要介紹了Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Java中實(shí)現(xiàn)文件預(yù)覽的功能(實(shí)例代碼)
大家都知道word,Excel,PPT實(shí)現(xiàn)在線預(yù)覽常用的方式就是先轉(zhuǎn)換成pdf,然后在進(jìn)行預(yù)覽,下面給大家介紹Java中如何實(shí)現(xiàn)文件預(yù)覽的功能,需要的朋友可以參考下2023-05-05Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔
這篇文章主要介紹了Spring Boot 使用 Swagger 構(gòu)建 RestAPI 接口文檔,幫助大家更好的理解和使用Spring Boot框架,感興趣的朋友可以了解下2020-10-10Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例
這篇文章主要介紹了Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例,本文直接給出編碼實(shí)例,需要的朋友可以參考下2015-05-05