解析和執行Jar包中的方法
1. 使用spring-boot 的打包插件
打包插件配置:pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
<configuration>
<layout>NONE</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
layout
配置爲 NONE
表示打包的結果包含所有依賴,並且不會包含spring-boot-loader。
spring-boot 打包插件的詳細,請參考官方文檔。
如 springbootjar ,使用 mvn clean package
打包後,jar 包的結構如下:
2. 核心代碼
工程依賴於 spring-boot-loader
,相關 pom
配置爲:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<version>2.1.3.RELEASE</version>
<scope>provided</scope>
</dependency>
新建一個類 MyLauncher
,繼承於 JarLauncher
,然後對外暴露一個方法,提供 ClassLoader,這個類加載器,就可以加載使用 spring-boot-maven-plugin
打的 jar 包中的方法了。
具體代碼如下:
package com.ysx.execute.utils;
import org.springframework.boot.loader.JarLauncher;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.jar.JarFile;
/**
* @author youngbear
* @email [email protected]
* @date 2019-04-01 07:45
* @blog https://blog.csdn.net/next_second
* @github https://github.com/YoungBear
* @description
*/
public class MyLauncher extends JarLauncher {
public MyLauncher(Archive archive) {
super(archive);
}
/**
* 獲取 ClassLoader
*
* @return
* @throws Exception
*/
public ClassLoader getClassLoader() throws Exception {
JarFile.registerUrlProtocolHandler();
ClassLoader classLoader = createClassLoader(getClassPathArchives());
return classLoader;
}
}
具體執行方法的代碼如下:
package com.ysx.execute.service.impl;
import com.google.gson.Gson;
import com.ysx.execute.entity.RequestExecuteEntity;
import com.ysx.execute.service.IExecuteService;
import com.ysx.execute.utils.MyLauncher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.loader.archive.JarFileArchive;
import org.springframework.stereotype.Service;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
/**
* @author youngbear
* @email [email protected]
* @date 2019-04-01 20:42
* @blog https://blog.csdn.net/next_second
* @github https://github.com/YoungBear
* @description
*/
@Service
public class ExecuteServiceImpl implements IExecuteService {
private static final Logger LOGGER = LoggerFactory.getLogger(ExecuteServiceImpl.class);
private static final Gson GSON = new Gson();
@Override
public String executeSpringBootJar(RequestExecuteEntity requestExecuteEntity) throws Exception {
String jarPath = requestExecuteEntity.getJarPath();
String className = requestExecuteEntity.getClassName();
String methodName = requestExecuteEntity.getMethodName();
List<String> paramClassNameList = requestExecuteEntity.getParamClassNameList();
List<String> paramJsonList = requestExecuteEntity.getParamJsonList();
// 使用本地jar文件,創建一個 JarFileArchive
JarFileArchive jarFileArchive = new JarFileArchive(new File(jarPath));
// 根據 JarFileArchive 創建一個 MyLauncher 對象,用於獲取 類加載器
MyLauncher myLauncher = new MyLauncher(jarFileArchive);
ClassLoader classLoader = myLauncher.getClassLoader();
// 使用類加載器,獲取相關 Class<?> 對象,最後使用反射調用方法
Class<?> aClass = classLoader.loadClass(className);
List<Class<?>> paramClassList = new ArrayList<>();
for (String paramClassName : paramClassNameList) {
paramClassList.add(classLoader.loadClass(paramClassName));
}
Class<?>[] paramClassArray = paramClassList.toArray(new Class<?>[0]);
List<Object> paramObjectList = new ArrayList<>();
for (int i = 0; i < paramJsonList.size(); i++) {
paramObjectList.add(GSON.fromJson(paramJsonList.get(i), paramClassList.get(i)));
}
Object[] paramObjectArray = paramObjectList.toArray(new Object[0]);
Method method = aClass.getDeclaredMethod(methodName, paramClassArray);
Object obj = aClass.newInstance();
Object result = method.invoke(obj, paramObjectArray);
LOGGER.info("result: {}", GSON.toJson(result));
// 執行完成後,關閉 ClassLoader
if (classLoader instanceof URLClassLoader) {
((URLClassLoader) classLoader).close();
}
return GSON.toJson(result);
}
}
3. 請求示例
本地使用 SpringBoot 啓動 execute 工程後(mvn spring-boot:run
),可以訪問SwaggerUI文檔地址:http://localhost:8080/swagger-ui.html
http 請求入參:
{
"className": "com.ysx.springbootjar.Hello",
"jarPath": "/Users/youngbear/Desktop/springbootjar-1.0-SNAPSHOT.jar",
"methodName": "method1",
"paramClassNameList": [
"com.ysx.springbootjar.param.InputParam"
],
"paramJsonList": [
"{\"in1\":\"in1ysx\",\"in2\":2}"
]
}
執行結果如下圖: