添加 spring-boot-jar-slim-encrypt 模块,包含 JAR 文件压缩和加密工具
- 实现了 `SpringBootJarSlimEncryptApplication` 用于处理使用 XJar 加密的 JAR 文件,并支持基于 XML 的包含/排除配置。 - 新增 Maven `pom.xml` 文件为新模块并设置必要的依赖(XJar、Dom4j、Hutool)。 - 引入了 `PlainTextClassLoader` 用于外部 JAR 文件的动态类加载。 - 修改根目录下的 `pom.xml` 文件以包含新的模块(`spring-boot-jar-slim-encrypt`、`thin-launcher-demo`、`spring-boot-custom-classloader`)。 - 添加了诸如 `JarUtil` 等工具类,用于处理 JAR 文件的操作和加密。
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package com.mangmang;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface JarClassLoader {
|
||||
String JAR_EXTENSION = ".jar";
|
||||
|
||||
/**
|
||||
* 从指定目录加载所有JAR文件
|
||||
*
|
||||
* @param jarDir 包含要加载的JAR文件的目录路径
|
||||
* @throws IllegalArgumentException 如果jarDir为null或不存在
|
||||
*/
|
||||
default void loadJar(String jarDir) {
|
||||
if (jarDir == null || jarDir.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("JAR目录路径不能为空");
|
||||
}
|
||||
|
||||
File directory = new File(jarDir);
|
||||
if (!directory.exists() || !directory.isDirectory()) {
|
||||
throw new IllegalArgumentException("指定路径不是有效目录: " + jarDir);
|
||||
}
|
||||
|
||||
File[] jarFiles = directory.listFiles(this::isJarFile);
|
||||
if (jarFiles == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File jarFile : jarFiles) {
|
||||
System.out.println("加载 》" + jarFile.getName());
|
||||
scanJarFile(jarFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归扫描文件或目录以查找JAR文件
|
||||
*
|
||||
* @param file 要扫描的文件或目录
|
||||
* @throws IllegalArgumentException 如果file为null
|
||||
*/
|
||||
default void scanJarFile(File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("文件不能为null");
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJarFile(file)) {
|
||||
addJARFile(file);
|
||||
} else if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
scanJarFile(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否为JAR文件
|
||||
*/
|
||||
default boolean isJarFile(File file) {
|
||||
return file.isFile() && file.getName().endsWith(JAR_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JAR文件添加到类加载器
|
||||
*
|
||||
* @param jar 要添加的JAR文件
|
||||
* @throws IllegalArgumentException 如果jar为null或不是有效的JAR文件
|
||||
*/
|
||||
void addJARFile(File jar);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.mangmang;
|
||||
|
||||
import org.springframework.boot.context.event.ApplicationStartingEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 明文类加载器
|
||||
* <p>
|
||||
* 该类实现了自定义类加载器接口和Spring应用启动事件监听器接口。
|
||||
* 主要功能是在应用启动时,从JVM启动参数中查找指定路径的JAR文件并加载。
|
||||
* 通过反射机制将JAR文件动态添加到当前线程的类加载器中,实现运行时加载额外的类库。
|
||||
* </p>
|
||||
* <p>
|
||||
* 使用方法:
|
||||
* 1. 在JVM启动参数中添加 -Dexternal.jars.path=你的JAR文件目录路径
|
||||
* 2. 系统将自动加载该目录下所有的JAR文件
|
||||
* </p>
|
||||
* <p>
|
||||
* 示例:
|
||||
* java -Dexternal.jars.path.path=/path/to/jars -jar your-application.jar
|
||||
* </p>
|
||||
*/
|
||||
public class PlainTextClassLoader implements JarClassLoader, ApplicationListener<ApplicationStartingEvent> {
|
||||
|
||||
private final String findPath = "external.jars.path"; // 查找路径的键名
|
||||
private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 获取当前线程的类加载器
|
||||
private final List<File> jarFiles = new ArrayList<>(); // 存储已加载的JAR文件列表
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* <p>
|
||||
* 在初始化时执行以下操作:
|
||||
* 1. 设置当前线程的类加载器
|
||||
* 2. 输出启动日志信息
|
||||
* 3. 从JVM启动参数中检索包含"external.jars.path.path"的参数
|
||||
* 4. 提取路径值并调用loadJar方法加载指定目录下的JAR文件
|
||||
* </p>
|
||||
*/
|
||||
public PlainTextClassLoader() {
|
||||
// 设置当前线程的类加载器
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
|
||||
// 打印启动信息
|
||||
System.out.println("启动自定义明文类加载器");
|
||||
|
||||
// 查找并加载外部JAR文件
|
||||
loadExternalJarsFromSystemProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从系统属性中查找并加载外部JAR文件
|
||||
*/
|
||||
private void loadExternalJarsFromSystemProperties() {
|
||||
List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
|
||||
|
||||
// 查找包含指定路径参数的启动参数
|
||||
inputArguments.stream()
|
||||
.filter(arg -> arg.contains(findPath))
|
||||
.map(this::extractPathFromArgument)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(this::loadJar);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从JVM参数中提取路径值
|
||||
*
|
||||
* @param argument JVM启动参数
|
||||
* @return 提取的路径值,如果提取失败则返回null
|
||||
*/
|
||||
private String extractPathFromArgument(String argument) {
|
||||
String prefix = "-D" + findPath + "=";
|
||||
if (argument.startsWith(prefix)) {
|
||||
String path = argument.replace(prefix, "");
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理应用程序启动事件
|
||||
* <p>
|
||||
* 当Spring应用启动时会触发此方法。
|
||||
* 目前该方法为空实现,可以在此添加应用启动时需要执行的代码。
|
||||
* </p>
|
||||
*
|
||||
* @param event Spring应用启动事件对象
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(@NonNull ApplicationStartingEvent event) {
|
||||
// 应用程序启动事件的处理方法,目前为空
|
||||
}
|
||||
|
||||
/**
|
||||
* 将JAR文件添加到类加载器
|
||||
* <p>
|
||||
* 通过反射机制调用URLClassLoader的addURL方法,将指定的JAR文件URL添加到当前类加载器。
|
||||
* 添加成功后,JAR文件中的类可以被当前JVM加载和使用。
|
||||
* 同时将已加载的JAR文件记录到jarFiles列表中。
|
||||
* </p>
|
||||
*
|
||||
* @param jar 要添加到类加载器的JAR文件对象
|
||||
* @throws RuntimeException 如果添加过程中发生任何异常,将抛出RuntimeException
|
||||
*/
|
||||
@Override
|
||||
public void addJARFile(File jar) {
|
||||
if (jar == null) {
|
||||
throw new IllegalArgumentException("JAR文件不能为null");
|
||||
}
|
||||
|
||||
try {
|
||||
addUrlToClassLoader(jar);
|
||||
jarFiles.add(jar);
|
||||
System.out.println(jarFiles);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("添加JAR文件到类加载器失败: " + jar.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射将JAR文件URL添加到类加载器
|
||||
*
|
||||
* @param jar 要添加的JAR文件
|
||||
* @throws Exception 如果反射操作失败
|
||||
*/
|
||||
private void addUrlToClassLoader(File jar) throws Exception {
|
||||
Method addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
if (!addUrlMethod.isAccessible()) {
|
||||
addUrlMethod.setAccessible(true);
|
||||
}
|
||||
URL jarUrl = jar.toURI().toURL();
|
||||
addUrlMethod.invoke(classLoader, jarUrl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.context.ApplicationListener=\
|
||||
com.mangmang.PlainTextClassLoader
|
||||
Reference in New Issue
Block a user