Java如何加载外部Jar的类并通过反射调用类的方法
问题
工作中遇到一个需求,客户端将第三方的 jar 包上传到服务器中,系统需要解析出上传的 jar 中所有类以及类下的方法(方法名,方法输入参数类型,方法返回值类型),并将这些类以及方法提供给配置人员选择,由配置人员自由配置需要用到的方法。
类加载器
Java 虚拟机在加载类文件时,默认情况下使用自带的三个类加载器
BootstrapClassLoader
:加载 %JRE_HOME%\jre\lib 下的 jar 和 classExtentionClassLoader
:加载 %JRE_HOME%\jre\lib\ext 下的 jar 和 classAppClassLoader
:加载当前应用路径下的 class
在 JDK 1.8 的 rt.jar 中,Launcher 类里定义了这三个类加载器
可以从源码中看到,三个加载器分别指定了不同的加载路径来加载类
BootstrapClassLoader
private static String bootClassPath = System.getProperty("sun.boot.class.path");
ExtentionClassLoader
System.getProperty("java.class.path")
AppClassLoader
System.getProperty("java.ext.dirs")
三个加载器通过双亲委派机制来加载类文件,每个加载器都只负责加载自己负责的加载路径,显然,如果要自定义加载路径,从而实现加载外部 jar 包,就必须自定义加载器来实现。
在 JDK 1.8 中,可以看到 AppClassLoader 和 ExtClassLoader 都是继承 URLClassLoader 来实现的。
若要加载外部的 jar 包,只需拿到外部 jar 包的 URL 路径,用 URLClassLoader 便可以加载。
获取外部 jar 包中的类以及方法
public class JarUtils { /** * 这些默认方法不打印 */ 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; //测试此枚举是否包含更多的元素 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(); //方法参数类型 System.out.print(String.format("方法参数类型:%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; } } }
调用外部 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里面的具体类对象 Class<?> targetClass = urlClassLoader.loadClass(className); //创建对象实例 Object instance = targetClass.newInstance(); //获取实例当中的方法名为show,参数只有一个且类型为string的public方法 Method method = targetClass.getMethod(methodName, classes); //传入实例以及方法参数信息执行这个方法 Object returnObj = method.invoke(instance, objects); System.out.println(returnObj); } catch (Exception e) { e.printStackTrace(); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Spring Boot中Reactor模型的基本概念和最佳实践
Reactor模型是一种基于事件驱动和非阻塞IO的编程模型,用于处理并发和异步操作,本文将介绍Spring Boot中使用Reactor模型的基本概念和最佳实践,帮助读者更好地理解如何利用这一强大的工具来构建现代化的Java应用程序,感兴趣的朋友跟随小编一起看看吧2024-05-05springboot 整合 nacos 配置实现多个环境不同配置
本文介绍了Nacos配置中心的优势,包括与Apollo的性能对比,Nacos服务端的安装与配置,以及如何在SpringBoot项目中集成Nacos进行多环境配置,提供了详细的步骤,包括下载、安装、配置中心的创建和项目集成,旨在帮助开发者更好地使用Nacos进行项目配置管理2024-09-09SpringBoot integration实现分布式锁的示例详解
常规项目都是采用Redission来实现分布式锁,进行分布式系统中资源竞争加锁操作,偶然发现SpringBoot中的integration也实现多种载体的分布式锁控制,下面我们就来看看具体实现方法吧2023-12-12Spring Boot 整合JPA 数据模型关联使用操作(一对一、一对多、多对多)
这篇文章主要介绍了Spring Boot 整合JPA 数据模型关联操作(一对一、一对多、多对多),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-07-07Java StringBuffer类与StringBuilder类用法实例小结
这篇文章主要介绍了Java StringBuffer类与StringBuilder类用法,结合实例形式总结分析了Java StringBuffer类与StringBuilder类的功能、原理及添加、删除、替换、截取等操作实现技巧,需要的朋友可以参考下2019-03-03
最新评论