动态加载执行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(带参数)
测试步骤
-
将TestJar打成jar包
-
将TestJar-1.0-SNAPSHOT.jar放在待测试的SpringBoot项目的resource/lib下
-
启动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;
}
}