读取嵌套jar包中的文件
读取jar包中的jar 文件
例如有一个Jar包 A.jar,他的目录文件如下图
A.jar |--B.jar |--Test.class |--.....
通过 new JarFile(A.jar)
可以等到A.jar 对应的对象,可以遍例A.jar中的所有文件,Jar包中的文件以 JarEntry
的形式保存数据 ,全码大致如下:
public void testJar() throws IOException { JarFile jarFile = new JarFile("C:\\Users\\Mzoro\\Desktop\\operation-1.1.jar"); System.out.println(jarFile.getName()); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); System.out.println(entry.getAttributes()); System.out.println(name); } }
但是 如果想继续遍历B.jar中的文件就不行了,需要其他方法,有一个活生生的例子是 spring-boot 打包后的jar 的运行过程
对应的java类的大致说明
一、嵌套jar的数据与信息获取方面
-
Archive,对jar包,或者目录的抽象
对jar包的抽象就是常见的,将spring-boot 工程发布成可执行jar 包,和嵌套其中的jar包与或目录,具体实现是
org.springframework.boot.loader.archive.JarFileArchive
;可以通过JarFileArchive
实例获取它的子目录或者嵌套的jar -
org.springframework.boot.loader.Launcher,真正的springboot启动类
这是一个抽象类,作用如下
-
创建具体的 Archive 实例(
Archive createArchive()
),JarFileArchive 还是WarFileArchive,具体是通过class文件的协议名来判定具体实例了。如果jar包启动,class 文件url前面的协议是以 jar:file开头的; 如果是war包,因为窗口会将war解压之后 再启动,所以class文件url的协议是file:// -
创建上下文的ClassLoader;用于加载嵌套包中的class 与 classes文件夹中的class。为什么要设置上下文classLoader呢?因为启动springboot 的jar包时的classpath 只有jre环境与 springboot 的jar包,如果用启动Launcher的ClassLoader会找不到类,所以要设置上下文ClassLoader 为LanuchedURLClassLoader
-
这个类声明了一个
abstract List<Archive> getClassPathArchives()
方法,抽象的,目的是返回ClassPath 下的jar包或者目录,为什么设置为abstract呢?因为 war与jar 的运行时依赖的lib 是在不同目录下的,class 也在不同目录下,同时还需要过滤掉一些不必要的jar 包或者war包中的东西,比如MANIFEST.MF
文件对加载类是没有用的,所有Archive 集合中没有必要包含它。这个方法的返回值会在构造LancherURLClassLoader时传入,在findClass时 会在这些Archive 代表的目录或者文件中查找Class文件
-
-
org.springframework.boot.loader.jar.JarFile
这个类继承自
java.util.jar.JarFile
, 主要重写的方法Enumeration<java.util.jar.JarEntry> entries()
; 它对应的是springboot jar中嵌套的jar ,这个类的主要作用是在构造时创建一个JarFileEntries
,这个类主要重写了entries()方法,而这个方法返回的Enumeration 是依靠JarFile持有的JarFileEnties获得的private JarFile(RandomAccessDataFile rootFile, String pathFromRoot, RandomAccessData data, JarEntryFilter filter, JarFileType type) throws IOException { super(rootFile.getFile()); this.rootFile = rootFile; this.pathFromRoot = pathFromRoot; CentralDirectoryParser parser = new CentralDirectoryParser(); this.entries = parser.addVisitor(new JarFileEntries(this, filter)); parser.addVisitor(centralDirectoryVisitor()); this.data = parser.parse(data, filter == null); this.type = type; }
-
org.springframework.boot.loader.jar.JarFileEntries
这个类的作用非常重要,它代表一个jar包中的所有Entries,并且这个类在构建时就保存了这个jar包中所有Entry的文件流信息,所有在通过这个类的对象获取具体的JarEnty对象时,JarEnty对象就可以包含entry对应的文件的真正的流数据。在definedClass方法的入参,byte[]是一个必须的参数
个人觉得难就难在这里,如何计算jar包中每个文件的流的偏移量,文件大小等这些信息
二、ClassLoader方面
-
LaunchedURLClassLoader
它继承自URLClassLoader,这个类相对LaunchedURLClassLoader 没有太大区别,主要的区别在于对包的定义,因为在定义包时要从嵌套jar 中获取MANIFEST.MF 信息
-
org.springframework.boot.loader.jar.Handler
因为 URLClassLoader在获取Class文件时需要通过 URL对象来获取,而这个url具体如何获取(或者说打开Connection),可以指定Handler,
org.springframework.boot.loader.jar.Handler
就是为了打开嵌套jar 连接延生的; 它是实现了java.net.URLStreamHandler
的类,URLStreamHandelr只有一个抽象方法,就是URLConnection openConnection(URL url)
-
JarURLConnection
可以通过这个类获取 InputStream了,有了InputStream 就可以等到 definedClass所需的byte[]参数,而这个
JarURLConnection
获取InputStream的方法是通过构建 JarURLConnection时的JarFile
来获取的,JarFile获取InputStream 的方法是通过其持有的JarFileEntries
来获取的 ,JarFileEntries
的获取方法就是读取jar 包的偏移量读取二进制数据
总结
看了一通代码最后感觉还是不能自己实现,难点在于读取嵌套jar包流的问题上在
疑问
代码上感觉spring-boot-loader
只处理了一层嵌套,不知道能不能处理多层的,当然,可能也没有人这么用;如果可以的话,那么除了springboot工程,其他工程有没有可能也使用这种方式进行打包并进行任意层的嵌套呢?感觉好蠢的想法
参考:
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
共克时艰,云端充电丨教育部创新团队首席专家焦李成教授做客CAAI云课堂第三期
疫情防控不放松,学习充电不间断。在此特殊时期,中国人工智能学会积极探索学术交流创新模式,围绕AI+学术、AI+技术以屏幕架起连接智能科技知识的桥梁,为学会会员和AI从业者特别开设CAAI云课堂等系列活动。学会集结优质讲师资源依托数字化平台,在中国科协绿平台的支持下,通过前沿优质的课程提供免费高质量的知识服务。让我们开启云端互动,与讲师面对面! No.1 第三期讲师 焦李成 西安电子科技大学计算机科学与技术学部主任、教授,CAAI第六/七届副理事长IEEE/IET/CAAI/CCF/CIE /CAA Fellow智能感知与图像理解教育部重点实验室主任、智能感知与计算国际联合研究中心主任、智能感知与计算国际合作联合实验室主任等,教育部科技委学部委员、教育部人工智能科技创新专家组专家,IET西安分会主席等,教育部创新团队首席专家。首批入选国家“百千万”人才工程(第一、二层次)。全国模范教师。获得青年科技奖,以及国家自然科学奖二等奖、省部级一等奖以上科技奖励十余项,五次获得国家优秀科技图书奖励和全国首届三个一百优秀图书奖。 No.2 精彩课程 本期焦李成教授直播课程主题为《基于类脑感知与认知的...
- 下一篇
CUBA Studio 13.1 发布,企业级应用开发平台
大家好,CUBA Studio 13.1 已发布,可以从这里下载最新版,或者直接在IDEA中更新CUBA插件。 CUBA Studio 13.1 主要修正以下问题: 1. 创建 front-end 模块时重复添加 REST API 依赖的问题 2. Studio 内置开发时容器 “Try shutdown” 功能不可用的问题 3. 新项目创建成功后会出现“NoSuchElementException“的问题 4. 新的登录界面模板缺失图标的问题 5. 创建枚举表单标题不正确的问题 6. 其它二十多项 Bug 修复 详细的Bug修复列表在这里。 CUBA Platform 是一款开源且免费的企业级应用开发框架,已有将近10年的发展历史,由俄罗斯的 Haulmont 公司开发。 CUBA Platform 已登陆中国,为中国开发人员提供了中文网站、中文学习资源、中文开发文档以及中文论坛,社区活跃度日益提升。有任何开发问题可访问 CUBA 平台中国官方网站来反馈和交流。 详细信息
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Mario游戏-低调大师作品
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G