背景
有些时候会遇到一些特殊情况需要紧急对线上应用进行修复,而且没有办法本地重新打包发布时,利用jar命令进行更新或打包会是处理该问题的一种方式。
比如:这次我们需要紧急更新线上应用中的xml文件内的一段sql语句。
jar命令详解
命令行输入jar
可以看到该命令用法如下:
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
-----------------------------------------------------------------------------------
其中 {ctxui} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一个
-----------------------------------------------------------------------------------
-c 创建新的 JAR 文件包
-t 列出 JAR 文件包的内容列表(配合grep命令筛选)
-x 从 JAR 文件中提取指定的 (或所有) 文件
-u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)
-i 为指定的 jar 文件生成索引信息
-----------------------------------------------------------------------------------
[vfmn0PMe] 中的选项可以任选,也可以不选,它们是 jar 命令的选项参数
-----------------------------------------------------------------------------------
-v 在标准输出中生成详细输出
-f 指定 JAR 文件名,通常这个参数是必须的
-m 指定需要包含的 MANIFEST 清单文件
-n 创建新档案后执行 Pack200 规范化
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不产生所有项的清单(MANIFEST〕文件,此参数会忽略 -m 参数
-----------------------------------------------------------------------------------
[jar-file] 即需要生成、查看、更新或者解开的 JAR 文件包,它是 -f 参数的附属参数
-----------------------------------------------------------------------------------
[manifest-file] 即 MANIFEST 清单文件,它是 -m 参数的附属参数
-----------------------------------------------------------------------------------
[entry-point] mian函数入口,它是 -e 参数的附属参数
-----------------------------------------------------------------------------------
[-C dir] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令跳转至该目录下,
再执行不带 -C 参数的 jar 命令,它只能在创建和更新 JAR 文件包的时候可用。
-----------------------------------------------------------------------------------
files ... 指定一个文件/目录列表(使用空格进行分隔),这些文件/目录就是要
添加到 JAR 文件包中的文件/目录。
如果指定了目录,那么 jar 命令打包的时候会自动把该目录中的所有文件和子目录打入包中。
-----------------------------------------------------------------------------------
注意:
清单文件名, 档案文件名和入口点名称的指定顺序与 '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/ .
方式一:提取/更新方式完成替换
- 通过命令查找文件相对路径
jar tvf test.jar | grep 'xxx.xml'
------显示如下------
6324 Thu May 19 15:55:32 CST 2022 BOOT-INF/classes/com/xxx/test/xxx.xml
- 根据路径提取文件
jar xvf test.jar BOOT-INF/classes/com/xxx/test/xxx.xml
文件会被提取到test.jar同级目录中并且路径与jar包中存在路径一致
- 针对得到文件进行修改或者替换
- 将新文件替换至jar包中
# 注意此处的 '0' 参数,springboot应用打包未使用压缩,所以此处必须设置
jar uvf0 test.jar BOOT-INF/classes/com/xxx/test/xxx.xml
- 以上操作,则完成了全部替换。(替换文件可以是:jar包、class文件、普通文件等全部文件)
方式二:采用打包方式替换
- 将jar包通过 7z 或者 The Unarchiver 等应用解压缩成目录
- 在解压后的目录中找到需要替换的文件,执行替换操作
- cd进目录,执行打包命令重新进行打包操作
# 注意此处的 '0' 参数,springboot应用打包未使用压缩,所以此处必须设置
jar cvfm0 test.jar META-INF/MANIFEST.MF .
- 以上操作,则完成了全部替换。
关于压缩后报错与参数 '0' 的问题
由于springboot规定嵌套的jar包不能在被压缩的情况下存储,因此如果打包或者更新命令未携带参数 '0' 的情况下,会出现如下报错:
Unable to open nested entry 'BOOT-INF/lib/xxx.jar'.
It has been compressed and nested jar files must be stored without compression.
此处需要注意。