Java动态执行jar包中类的方法

动态加载执行jar包,在实际开发中经常会需要用到,尤其涉及平台和业务的关系的时候,业务逻辑部分可以独立出去交给业务方管理,业务方只需要提供jar包,就能在平台上运行。

结论

通过反射可以实现动态调用jar包中的类的方法

环境

jdk8

Springboot 2.7.14

测试环境介绍

新建一个SpringBoot项目,提供Controller的两个访问接口;m1接口调用jar包中的TestClass的m1方法;m2接口调用jar包中的TestClass的m2方法;

TestJar的包名:test.jar

TestJar下的测试类:TestClass

方法1:m1

方法2:m2(带参数)

测试步骤

  1. 将TestJar打成jar包

  2. 将TestJar-1.0-SNAPSHOT.jar放在待测试的SpringBoot项目的resource/lib下

  3. 启动SpringBoot项目,访问接口m1、m2

关键代码

TestController.java

java 复制代码
package cn.only.hww.test.controller;

import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;

/**
 * author       : Wayne Hu
 * date created : Created in 2024/7/8 11:32
 * description  :
 * class name   : TestController
 */
@RestController
@RequestMapping("test")
public class TestController {
    // 从resources目录加载jar文件
    ClassPathResource resource = new ClassPathResource("lib/TestJar-1.0-SNAPSHOT.jar");
    File jarFile = new File(System.getProperty("java.io.tmpdir") + "/TestJar-1.0-SNAPSHOT.jar");



    @GetMapping("m1")
    public String test1() {
        String result = null;
        try {

            // 创建URLClassLoader加载jar包
            URL jarUrl = jarFile.toURI().toURL();
            URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, TestController.class.getClassLoader());

            // 加载类并调用方法
            Class<?> testClass = classLoader.loadClass("test.jar.TestClass");
            Object testClassInstance = testClass.getDeclaredConstructor().newInstance();
            FileCopyUtils.copy(resource.getInputStream(), Files.newOutputStream(jarFile.toPath()));

            Method m1Method = testClass.getMethod("m1");
            result = (String) m1Method.invoke(testClassInstance);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "test1 result: " + result;
    }

    @GetMapping("m2")
    public String test2() {
        String result = null;
        try {
            FileCopyUtils.copy(resource.getInputStream(), Files.newOutputStream(jarFile.toPath()));

            // 创建URLClassLoader加载jar包
            URL jarUrl = jarFile.toURI().toURL();
            URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, TestController.class.getClassLoader());

            // 加载类并调用方法
            Class<?> testClass = classLoader.loadClass("test.jar.TestClass");
            Object testClassInstance = testClass.getDeclaredConstructor().newInstance();
            Method m1Method = testClass.getMethod("m2", String.class);
            String param = "{'user':'admin'}";
            result = (String) m1Method.invoke(testClassInstance, param);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "test1 result: " + result;
    }
}

TestClass.java

java 复制代码
package test.jar;

/**
 * author       : Wayne Hu
 * date created : Created in 2024/7/8 11:37
 * description  :
 * class name   : TestClass
 */
public class TestClass {
    public String m1(){
        System.out.println("执行jar包方法1");
        return "我是来自jar包的m1方法的返回数据";
    }

    public String m2(String data){
        System.out.println("执行jar包方法2,参数为:" + data);
        return "我是来自jar包的m2方法的返回数据,参数为:" + data;
    }
}
相关推荐
美味小鱼3 分钟前
Rust场景示例:为什么要使用切片类型
开发语言·rust
LUCIAZZZ1 小时前
手写单例模式
java·开发语言·spring boot·单例模式
程序员东min2 小时前
C++:抽象类习题
开发语言·c++
二十雨辰4 小时前
[Java基础]开发工具Idea
java·intellij-idea
摸鱼仙人~4 小时前
Git如何避免推送.idea文件夹
java·git·intellij-idea
zzb15804 小时前
项目集成Spring Security认证部分
java·后端·spring
程序猿小D5 小时前
第三百五十八节 JavaFX教程 - JavaFX滑块
java·前端·数据库
行路见知6 小时前
1.5 Go切片使用
开发语言·golang
基础不牢,地动山摇...8 小时前
tomcat核心组件及原理概述
java·tomcat
苏-言8 小时前
Maven全解析:从基础到精通的实战指南
java·maven