当前位置: 首页 > article >正文

Java JAR命令打包详解与坑点

一、背景

        同事从第三方厂家得到了jar包,但是由于里面的一个java代码逻辑需要自己适配,在拿到源代码以后,修改了一点逻辑,最后编译生成新的class文件。我们暂且把这个文件叫Business.class。

        原jar能直接运行,没有任何问题。按照替换的逻辑,我们很快能想到,就是把jar包使用windows解压工具进行解压,然后把class文件放到对应的路径,最后再zip打包为.jar文件即可。但是不出意外,还是出意外了。 

        通过zip打的包通过java -jar运行报错:

HelloWorld.jar中没有主清单属性

        仅仅只是替换了个class文件,报这个错误,让人摸不着头脑。下面就是我们的排坑之路~,花了几个小时,最后才搞定。

二、排查过程

1、针对新jar包解压,查看META-INF/MANIFEST.MF

        查看了元信息文件,描述的程序入口Main-Class也是正确的。没啥毛病。 因为我们做的操作很简单,就是替换了一个class文件,整个jar都没起来。 那怀疑是通过zip打包的方式可能存在问题

2、旧jar包与新jar包同时解压,使用diff -r 递归对比2个目录看差异

        diff -r $old_dir  $new_dir  对比了一下,就是我们替换的那个class文件存在的jar包有差异,再继续解压里面的jar,查看文件对比,最终锁定,就只有Hello.class有差异,其它一样。

3、查看jar打包和zip直接打包的区别

        通过资料查询到,  通过jar命令打包和zip直接打包,还是存在差别的。 其中存在一个差别就是,jar有一个参数0,0的意思就是只是打包不压缩。 但是可能我们使用windows可视化工具直接修改保存之后,默认就是使用了压缩算法,导致java -jar运行的时候,无法解析那个被压缩的jar文件,导致报错。

4、使用jar cvfM0 Hello.jar *的方式解决问题

使用以下jar打包命令之后,打出的新jar包能正常运行:

jar cvfM0 Hello.jar *

参数解释:

c:   创建一个jar文件

f:   文件名称

v:   显示打包log过程

M:  不创建新的META-INFO和MAIFEST.MF文件,直接使用原项目的

0:    不使用任何压缩算法,只是对打包的文件/目录进行原样打包,不压缩

5、结论验证

        为了验证我们的分析结论,通过unzip -v $jar 查看每个文件打包使用的压缩算法,对比下什么情况:

      左边是存在文件的jar包(基于旧jar包,重新替换了一个Hello.class文件), 右边是旧jar包(正常运行的)。

        内部相同依赖的jar文件 ,我们看到左边采用了压缩算法,压缩了15%的内容。 右边Stored表示没有使用压缩算法,原样打包。  

        由此可见和我们的猜想是一样的。

三、jar打包命令详解

1、jar --help查看帮助信息

非法选项: -
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
    -c  创建新档案
    -t  列出档案目录
    -x  从档案中提取指定的 (或所有) 文件
    -u  更新现有档案
    -v  在标准输出中生成详细输出
    -f  指定档案文件名
    -m  包含指定清单文件中的清单信息
    -n  创建新档案后执行 Pack200 规范化
    -e  为捆绑到可执行 jar 文件的独立应用程序
        指定应用程序入口点
    -0  仅存储; 不使用任何 ZIP 压缩
    -P  保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
    -M  不创建条目的清单文件
    -i  为指定的 jar 文件生成索引信息
    -C  更改为指定的目录并包含以下文件
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序
与 'm', 'f' 和 'e' 标记的指定顺序相同。

示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中: 
       jar cvf classes.jar Foo.class Bar.class 
示例 2: 使用现有的清单文件 'mymanifest' 并
           将 foo/ 目录中的所有文件归档到 'classes.jar' 中: 
       jar cvfm classes.jar mymanifest -C foo/ .

2、参数详解( 'm', 'f' 和 'e' 标记的指定顺序相同)

1、-c 、-f、-v

-c 表示需要创建一个jar

-f  指明jar包的文件名称

-v  在标准输出中生成详细输出

2、-t  预览jar包内容
jar -tf  hello.jar   #预览查看hello.jar文件内容
3、-u  添加/更新文件

   如果需要更新jar里面的文件,可以直接进行更新。  但是本地目录和jar里面的路径要保持一致(文件覆盖场景)

4、-x解压文件或者全部解压jar

   -x可以解压Hello.jar

5、-0 仅存储; 不使用任何 ZIP 压缩

    -0 原样添加打包,不会对源文件进行压缩

6、-m、-M 

    -m  包含指定清单文件中的清单信息(创建META-INF)
    -M  不创建条目的清单文件(使用原有的jar的META-INF结构)

7、-C

        -C  更改为指定的目录并包含以下文件

3、常用场景指令

1、打包创建jar文件
jar cvf  Hello.jar *   #常见打包方式

jar cvfM0 Hello.jar *  #-0不压缩,打包方式
2、解压jar文件
jar xvf Hello.jar  #解压jar包
3、更新文件
jar uf Hello.jar  com/bes/Hello.class
4、预览jar内容
jar tf Hello.jar #预览Hello.jar文件内容
5、查看jar压缩详情
unzip -v Hello.jar  #查看jar包,打包详情(是否使用压缩、使用哪些压缩算法)

四、总结

   建议还是按照java规范,使用jar命令进行打包处理,而不是简单的zip命令进行打包。 但是也不是一概而论,如果先通过zip没问题就可以,如果存在问题回到原点,使用jar打包即可。

    特别注意-0参数是否需要,否则会造成上述的问题。


http://www.kler.cn/news/290616.html

相关文章:

  • 【适配器】设计模式:旧系统迁移与第三方库集成的解决方案
  • ElasticSearch-聚合操作
  • 【大数据】浅谈Pyecharts:数据可视化的强大工具
  • MySQL数据库安装(详细)—>Mariadb的安装(day21)
  • Linux教程8:文本编辑命令vi
  • css画个熊猫
  • 面试(九)
  • SAP HCM 如何追踪Z表的日志修改记录
  • Docker 入门指南:从安装到第一个容器
  • 安装vue-cli2.0并创建项目
  • 我该如何使用DevEco Studio进行开发呢
  • 09-02 周一 elasticsearch使用指南
  • Android U 多任务启动分屏——Launcher流程(更新中)
  • 自定义全局变量在uniapp的Vuex应用
  • 人工智能与机器学习原理精解【17】
  • 【JUnit单元测试框架】
  • vite 打包 学习
  • 能实现可算不可见的同态加密技术详解
  • PDF招生简章如何转二维码?
  • PostgreSQL分区表原理、案例的灵活应用
  • EventBus-Vue事件总线解析与使用指南
  • C++学习笔记(6)
  • C++11中的static_assert运算
  • 初学者指南:Spring Boot入门
  • 无人机的核心技术!!!
  • 打通Vue3+Flask(python3)+Mysql-实现简单数据交互
  • 会议音频方案
  • 2024.9.2
  • Orcad封装怎么添加
  • (每日一问)基础知识:Java垃圾回收机制详解