Java解析嵌套jar中class文件过程
一、简述
用Ma ven构建项目,最终打包成jar文件时,一个常见的结果是:这个jar包里,不仅包含了你自己的代码,还打包了所有依赖的库文件。这就形成了一个“嵌套”的结构。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

那么问题来了,如果想直接从这个“大包”里,解析出嵌套在内部那些依赖jar包中的class文件,该怎么办?别急,下面就来聊聊两种主流且实用的方法:一种是借助Spring Boot生态里的spring-boot-loader包提供的JarFileArchive;另一种则是使用Ja va标准库里的ja va.util.jar.JarFile。两种方式各有特点,咱们逐一拆解。
二、JarFileArchive方式
1. spring-boot-loader依赖引入
要使用第一种方法,首先得把工具包引入项目。在Ma ven的pom.xml里加上下面这段依赖即可:
org.springframework.boot spring-boot-loader 2.2.4.RELEASE
注意,版本号可以根据实际情况调整。
2. demo案例
这里有个细节需要提醒:不同版本的spring-boot-loader,其getNestedArchives方法签名可能不同。比如在较早版本中用的方法,在高版本里可能已被标记为废弃,转而使用参数更丰富的新方法。所以,实际编码时最好跟进一下你所使用版本的官方源码,做相应调整。
核心逻辑其实很清晰,看下面的代码示例就明白了:
public static void main(String args[]) throws Exception {
String jarPath = "C:\\Users\\root\\Desktop\\make-test.jar";
// 方案一:spring-boot-loader
long start1 = System.currentTimeMillis();
getClassInfoByJarLib(jarPath);
long end1 = System.currentTimeMillis();
log.info("收集所有lib类ClassInfo,花费时间={}",(end1-start1));
}
public static void getClassInfoByJarLib(String jarPath) {
String filePath;
String separator = File.separator;
if("\\".equals(separator)){
// windows系统使用如下路径
filePath = "file:/"+ URLDecoder.decode(jarPath, StandardCharsets.UTF_8).replaceAll("\\\\","/")+"!/";
}else if("/".equals(separator)){
// linux系统使用如下路径
filePath = "file:"+ URLDecoder.decode(jarPath, StandardCharsets.UTF_8).replaceAll("\\\\","/")+"!/";
}else {
throw new RuntimeException("未知操作系统,解析jarLib失败");
}
String rootJarPath = "jar:"+ filePath;
try {
JarFileArchive jarFileArchive = new JarFileArchive(new Handler().getRootJarFileFromUrl(new URL(rootJarPath)));
// getNestedArchives获取嵌套的jar等文件,参数是个EntryFilter,用于过滤
jarFileArchive.getNestedArchives(entry -> entry.getName().startsWith("BOOT-INF/lib/") && entry.getName().endsWith(".jar"))
.forEach(archive -> {
archive.iterator().forEachRemaining(entry -> {
String entryName = entry.getName();
// 过滤出嵌套jar包中的字节码文件
if (entryName.endsWith(".class")) {
String className = entryName.replace('/', '.').replace(".class", "");
log.info("className:{}",className);
}
});
});
} catch (IOException e) {
log.error("解析嵌套jarLib中ClassInfo异常,jarPath={}",jarPath,e);
throw new RuntimeException(e);
}
}
这段代码的关键在于,它利用JarFileArchive这个封装好的工具,能够非常方便地遍历出嵌套在BOOT-INF/lib/目录下的所有jar包,并进一步解析出里面的每一个class文件。路径处理和异常捕获也都考虑进去了,开箱即用。
三、JarFile方式
1. demo案例
如果你不想引入额外的依赖,纯用JDK自带的能力行不行?当然可以。Ja va标准库中的JarFile类同样能完成这个任务,只不过需要自己多写几行处理逻辑。
public static void main(String args[]) throws Exception {
String jarPath = "C:\\Users\\root\\Desktop\\make-test.jar";
// 方案二:JarFile
long start2 = System.currentTimeMillis();
processJar(jarPath);
long end2 = System.currentTimeMillis();
log.info("收集所有lib类ClassInfo,花费时间={}",(end2-start2));
}
private static void processJar(String jarPath){
try (JarFile jarFile = new JarFile(new File(jarPath))) {
jarFile.stream().parallel()
// 过滤出所有符合要求的jar包
.filter(entry -> !entry.isDirectory() && entry.getName().startsWith("BOOT-INF/lib/") && entry.getName().endsWith(".jar"))
.forEach(entry -> processNestedJar(jarFile, entry.getName()));
} catch (IOException e) {
log.error("解析嵌套jarLib中ClassInfo异常,jarPath={}",jarPath,e);
throw new RuntimeException(e);
}
}
private static void processNestedJar(JarFile jarFile, String entryName){
// 处理嵌套jar文件
try (InputStream nestedJarStream = jarFile.getInputStream(jarFile.getJarEntry(entryName));
JarInputStream jarInputStream = new JarInputStream(nestedJarStream)) {
JarEntry nestedEntry;
while ((nestedEntry = jarInputStream.getNextJarEntry()) != null) {
if (nestedEntry.isDirectory()) {
continue;
}
String nestedEntryName = nestedEntry.getName();
if (!nestedEntryName.endsWith(".class")) {
continue;
}
try {
String className = nestedEntryName.replace('/', '.').replace(".class", "");
log.info("className:{}",className);
} catch (Exception e) {
log.error("目标类={}查找失败",nestedEntryName,e);
throw new RuntimeException(e);
}
}
} catch (IOException e) {
log.error("目标类={}查找失败",entryName,e);
throw new RuntimeException(e);
}
}
这种方式的核心是使用JarFile和JarInputStream进行两层遍历。第一层找到嵌套的jar包,第二层再像解压缩一样,逐个读取嵌套jar里的class条目。代码量稍多,但胜在零依赖,理解起来也更底层。
四、两种方式对比
光说不练假把式,性能如何还得看实测。我们用一个名为make-test.jar的实际项目进行测试,其中大约包含了200个依赖lib,总计超过7万个class字节码文件。
结果很有意思:
- 使用
JarFileArchive方案,解析全部文件大约耗时 1.5秒。 - 使用标准
JarFile方案,完成同样的工作则花了大约 6秒。
差距显而易见。这主要是因为spring-boot-loader中的JarFileArchive为这种嵌套场景做了深度优化,封装了更高效的遍历逻辑。而纯JDK方案虽然通用,但在处理大量嵌套条目时,性能开销相对较大。
总结
简单总结一下:如果你的项目已经是Spring Boot体系,或者不介意引入一个轻量级的工具包,那么JarFileArchive无疑是更高效、更优雅的选择。如果你追求极致的“纯净”,或者只是在写一个简单的工具,那么基于标准JarFile的方案也能可靠地完成任务,只是需要多付出一点时间成本。
两种方法的核心思路和代码实现都在上面了,可以根据自己的实际场景灵活选用。希望这份梳理能为大家在处理类似问题时,提供一个清晰的参考。
您可能感兴趣的文章:
- ja va开发读取嵌套jar包中的文件
- windows后台运行Ja va jar包实现方式
- Ja va中-jar命令参数设置的完整指南
- Ja va JAR包运行与反编译实践
- ja va -jar启动原理详解(附实操验证和注意事项)
- mysql-connector-ja va.jar包的下载实践
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Linux C++如何实现高效的并发控制
在Linux环境下使用C++实现高效的并发控制 在Linux平台上利用C++构建高性能应用,并发控制是核心技术挑战。开发者需要掌握一系列工具与策略,并根据实际应用场景进行精准选择和组合,才能实现真正高效的并发编程。本文将系统梳理Linux C++并发编程的核心方法与最佳实践。 1 多线程编程 多线
如何正确使用 calendar.add 处理跨月或跨年的日期计算
理解 calendar add 方法的基本逻辑在处理日期和时间相关的编程任务时,calendar add 方法是一个常用且强大的工具。它的核心功能在于对日历字段进行算术运算,允许开发者方便地对日期进行加减操作,例如增加若干天、月或年。该方法的设计逻辑是“智能”地处理字段溢出,这意味着当对某个字段进行
Debian系统Rust库如何更新
在 Debian 系统中更新 Rust 库,操作流程并不复杂,关键在于准确识别库的初始安装来源。不同的安装方式对应着截然不同的更新策略。总体而言,主要分为两大场景:一是通过系统包管理器 APT 安装的系统级库,二是通过 Rust 包管理器 Cargo 管理的项目级依赖。本文将详细解析这两种场景下的安
解决Composer报Xdebug开启警告_关调试提运行速度【性能优化】
彻底解决Composer Xdebug警告:关闭调试以大幅提升运行效率 在使用Composer时遇到“Xdebug已开启”的警告提示?这不仅是简单的提示信息,更意味着您的PHP依赖管理操作正承受着显著的性能损失。当您在命令行界面执行 composer install 或 composer updat
Apache配置中如何实现重定向
Apache服务器URL重定向配置详解 在Apache网站服务器中,实现URL重定向与地址跳转是网站运维和SEO优化的常见需求。mod_rewrite模块作为Apache最强大的重写引擎,能够灵活处理各种复杂的URL重写逻辑。本文将系统讲解Apache配置重定向的完整步骤,并提供可直接使用的代码示例
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

