【Java后端】使用反射获得jar包中的类、方法、参数、返回值类型,然后动态加载jar包运行方法

关键词:[Java] [反射] [invoke]

其实我的需求是在系统中 测试用户导入的jar包,所有网上找了很多解决方案,踩过很多坑,再加上以前搞c++的,对java不是很熟,这里特意记录下,算是基本满足需求了;

使用反射获得jar包中的类、方法、参数、返回值类型

使用反射获取jar包中的类、方法、参数、以及返回类型,主要参照这篇文章
https://blog.csdn.net/chen7019/article/details/105708338

这里面我的TestJar.jar 里面 就一个Demo类,是这样的:

package com.baidu;

public class Demo {
    public Demo() {
    }

    public static void main(String[] args) {
    }

    public String getInfo() {
        return "hello world";
    }

    public int getSum(int a, int b) {
        return a + b;
    }
}

    @Test
    public void test2() {
        String path = "E:\\Desktop\\Programmer\\JavaFile\\MyWeb\\test\\web\\WEB-INF\\lib\\";
        String fileName = "TestJar.jar";
        try {
            JarFile jarFile = new JarFile(path + fileName);

            Enumeration<JarEntry> e = jarFile.entries();

            JarEntry entry;
            while (e.hasMoreElements()) {
                entry = (JarEntry) e.nextElement();
                //
                if (entry.getName().indexOf("META-INF") < 0 && entry.getName().indexOf(".class") >= 0) {
                    String classFullName = entry.getName();
                    //去掉后缀.class
                    String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
                    System.out.println(className);

                    Class<?> c = null;
                    try {
                        try {
                            // 用className这个类来装载c,但还没有实例化
                            c = Class.forName(className);
                        } catch (ClassNotFoundException e1) {
                            e1.printStackTrace();
                        }
                        Method[] methods = c.getMethods();
                        for (Method method : methods) {
                            String methodName = method.getName();
                            System.out.println("方法名称:" + methodName);
                            System.out.println("返回值类型" + method.getReturnType());
                            Class<?>[] parameterTypes = method.getParameterTypes();
                            for (Class<?> clas : parameterTypes) {
                                // String parameterName = clas.getName();
                                String parameterName = clas.getSimpleName();
                                System.out.println("参数类型:" + parameterName);
                            }
                            System.out.println("==========================");
                        }
                    } catch (Exception e1) {

                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行代码后的输出结果

com.baidu.Demo
方法名称:main
返回值类型void
参数类型:String[]
==========================
方法名称:getSum
返回值类型int
参数类型:int
参数类型:int
==========================
方法名称:getInfo
返回值类型class java.lang.String
==========================
方法名称:wait
返回值类型void
参数类型:long
参数类型:int
==========================
方法名称:wait
返回值类型void
==========================
方法名称:wait
返回值类型void
参数类型:long
==========================
方法名称:equals
返回值类型boolean
参数类型:Object
==========================
方法名称:toString
返回值类型class java.lang.String
==========================
方法名称:hashCode
返回值类型int
==========================
方法名称:getClass
返回值类型class java.lang.Class
==========================
方法名称:notify
返回值类型void
==========================
方法名称:notifyAll
返回值类型void
==========================

Process finished with exit code 0

如何动态实例化一个类,并运行其中的方法

//用className来状态这个c,className就是上面那个代码中的,可以理解为com.xxx.xxx(去掉了后面的.class)
Class<?> c = null;
c = Class.forName(className);
//创建对象实例
Object instance=c.newInstance();

这样还不能直接调用instance的方法,要先获取 这个类中的方法 然后再 invoke;
这里我以 TestJar.jar 里面的demo 类下的 getInfo 方法为例:

// 用className这个类来装载c
c = Class.forName(className);
// 实例化对象
Object instance=c.newInstance();
//获取实例当中的方法名为show,参数只有一个且类型为string的public方法
Method method=c.getMethod("getInfo");
// 如果该方法有参数,后面就跟参数类型
// Method method = MyTest.getMethod("show", String.class);

//  //传入实例以及方法参数信息(如果有)执行这个方法
Object ret = method.invoke(instance);

System.out.println("运行动态装载jar包的getInfo方法,并获得输出");
// 如果有返回值,可以直接打印ret获得输出
System.out.println(method.invoke(instance ));

全部代码

    public void test2() {
        String path = "E:\\Desktop\\Programmer\\JavaFile\\MyWeb\\test\\web\\WEB-INF\\lib\\";
        String fileName = "TestJar.jar";
        try {
            JarFile jarFile = new JarFile(path + fileName);

            Enumeration<JarEntry> e = jarFile.entries();

            JarEntry entry;
            while (e.hasMoreElements()) {
                entry = (JarEntry) e.nextElement();
                //
                if (entry.getName().indexOf("META-INF") < 0 && entry.getName().indexOf(".class") >= 0) {
                    String classFullName = entry.getName();
                    //去掉后缀.class
                    String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
                    System.out.println(className);

                    Class<?> c = null;
                    try {
                        try {
                            // 用className这个类来装载c
                            c = Class.forName(className);
                            Object instance=c.newInstance();
                            Method method=c.getMethod("getInfo");
                            System.out.println("运行动态装载jar包的getInfo方法,并获得输出");
                            System.out.println(method.invoke(instance ));
                        } catch (ClassNotFoundException e1) {
                            e1.printStackTrace();
                        }
                        Method[] methods = c.getMethods();
                        for (Method method : methods) {
                            String methodName = method.getName();
                            System.out.println("方法名称:" + methodName);
                            System.out.println("返回值类型" + method.getReturnType());
                            Class<?>[] parameterTypes = method.getParameterTypes();
                            for (Class<?> clas : parameterTypes) {
                                // String parameterName = clas.getName();
                                String parameterName = clas.getSimpleName();
                                System.out.println("参数类型:" + parameterName);
                            }
                            System.out.println("==========================");
                        }
                    } catch (Exception e1) {

                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

输出

com.baidu.Demo
运行动态装载jar包的getInfo方法,并获得输出
hello world
方法名称:main
返回值类型void
参数类型:String[]
==========================
方法名称:getSum
返回值类型int
参数类型:int
参数类型:int
==========================
方法名称:getInfo
返回值类型class java.lang.String
==========================
方法名称:wait
返回值类型void
参数类型:long
参数类型:int
==========================
方法名称:wait
返回值类型void
==========================
方法名称:wait
返回值类型void
参数类型:long
==========================
方法名称:equals
返回值类型boolean
参数类型:Object
==========================
方法名称:toString
返回值类型class java.lang.String
==========================
方法名称:hashCode
返回值类型int
==========================
方法名称:getClass
返回值类型class java.lang.Class
==========================
方法名称:notify
返回值类型void
==========================
方法名称:notifyAll
返回值类型void
==========================

Process finished with exit code 0

用getSum方法也是一样:

c = Class.forName(className);
Object instance=c.newInstance();
Method method=c.getMethod("getSum",int.class,int.class);
System.out.println("运行动态装载jar包的getSum方法,并获得输出");
System.out.println(method.invoke(instance,2,3));
com.baidu.Demo
运行动态装载jar包的getSum方法,并获得输出
5
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要读取指定jar包,可以使用Java反射机制。首先需要使用Java加载器来加载指定的jar包,然后使用反射机制来获取该jar包的所有。 以下是读取指定jar包所有的示例代码: ```java import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class JarReader { public static void main(String[] args) throws IOException, ClassNotFoundException { // 指定jar包的路径 String jarPath = "path/to/your/jar/file.jar"; // 创建URLClassLoader来加载指定的jar包 URL[] urls = { new URL("file:" + jarPath) }; ClassLoader cl = new URLClassLoader(urls); // 创建JarFile来读取jar包的内容 JarFile jarFile = new JarFile(new File(jarPath)); // 遍历jar包的所有 Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (entry.getName().endsWith(".class")) { // 使用Class.forName方法加载 Class<?> clazz = cl.loadClass(entry.getName().replaceAll("/", ".").replaceAll(".class", "")); // 处理获取到的,例如获取方法和属性 // ... } } // 关闭JarFile jarFile.close(); } } ``` 在这个示例代码,我们首先指定了要读取的jar包的路径,然后创建了一个URLClassLoader来加载jar包。接着使用JarFile来读取jar包的内容,并遍历所有的。对于每个使用Class.forName方法加载,并处理获取到的,例如获取方法和属性。 需要注意的是,这个示例代码只是演示了如何读取指定jar包的所有,并没有对获取到的进行实际的处理。实际使用时,需要根据具体的需求来处理获取到的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值