当前位置: 首页
编程语言
Java解析嵌套jar中class文件过程

Java解析嵌套jar中class文件过程

热心网友 时间:2026-04-22
转载

一、简述

用Ma ven构建项目,最终打包成jar文件时,一个常见的结果是:这个jar包里,不仅包含了你自己的代码,还打包了所有依赖的库文件。这就形成了一个“嵌套”的结构。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

Ja va解析嵌套jar中class文件过程

那么问题来了,如果想直接从这个“大包”里,解析出嵌套在内部那些依赖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);
        }
    }

这种方式的核心是使用JarFileJarInputStream进行两层遍历。第一层找到嵌套的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包的下载实践
来源:https://www.jb51.net/program/3625946lx.htm

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Linux C++如何实现高效的并发控制

Linux C++如何实现高效的并发控制

在Linux环境下使用C++实现高效的并发控制 在Linux平台上利用C++构建高性能应用,并发控制是核心技术挑战。开发者需要掌握一系列工具与策略,并根据实际应用场景进行精准选择和组合,才能实现真正高效的并发编程。本文将系统梳理Linux C++并发编程的核心方法与最佳实践。 1 多线程编程 多线

时间:2026-04-22 13:18
如何正确使用 calendar.add 处理跨月或跨年的日期计算

如何正确使用 calendar.add 处理跨月或跨年的日期计算

理解 calendar add 方法的基本逻辑在处理日期和时间相关的编程任务时,calendar add 方法是一个常用且强大的工具。它的核心功能在于对日历字段进行算术运算,允许开发者方便地对日期进行加减操作,例如增加若干天、月或年。该方法的设计逻辑是“智能”地处理字段溢出,这意味着当对某个字段进行

时间:2026-04-22 13:16
Debian系统Rust库如何更新

Debian系统Rust库如何更新

在 Debian 系统中更新 Rust 库,操作流程并不复杂,关键在于准确识别库的初始安装来源。不同的安装方式对应着截然不同的更新策略。总体而言,主要分为两大场景:一是通过系统包管理器 APT 安装的系统级库,二是通过 Rust 包管理器 Cargo 管理的项目级依赖。本文将详细解析这两种场景下的安

时间:2026-04-22 12:28
解决Composer报Xdebug开启警告_关调试提运行速度【性能优化】

解决Composer报Xdebug开启警告_关调试提运行速度【性能优化】

彻底解决Composer Xdebug警告:关闭调试以大幅提升运行效率 在使用Composer时遇到“Xdebug已开启”的警告提示?这不仅是简单的提示信息,更意味着您的PHP依赖管理操作正承受着显著的性能损失。当您在命令行界面执行 composer install 或 composer updat

时间:2026-04-22 12:14
Apache配置中如何实现重定向

Apache配置中如何实现重定向

Apache服务器URL重定向配置详解 在Apache网站服务器中,实现URL重定向与地址跳转是网站运维和SEO优化的常见需求。mod_rewrite模块作为Apache最强大的重写引擎,能够灵活处理各种复杂的URL重写逻辑。本文将系统讲解Apache配置重定向的完整步骤,并提供可直接使用的代码示例

时间:2026-04-22 11:49
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程