jar包中内容的修改方法

1背景

实际工作过程中,项目部署一般是在内网中,如果发现后端代码有问题,有时候只是简单修改逻辑,改两三个文件,外网打包重传比较麻烦,如果外面再套一个几个G的基础镜像,那浪费的时间非常多,如果能在内网内直接修改代码并重新编译打包 能节省巨多时间,特别是遇到传数据按天计算的情况

2前置条件:

操作环境需要有jdk 和arthas工具

jar包含有所有依赖的第三方jar包

使用的示例为 mybatis-flex的示例代码的mybatis-flex-springboot(简单修改了pom 使用了springboot-mavne插件)项目与arthas自带的math-game.jar gitee.com/mybatis-fle...

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.9</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
...其他内容省略 plugin中注释掉了原来的编译插件 改用springboot-maven插件编译出的jar包 包含所有依赖..
   <plugins>
<!--            <plugin>-->
<!--                <groupId>org.apache.maven.plugins</groupId>-->
<!--                <artifactId>maven-compiler-plugin</artifactId>-->
<!--                <version>3.8.1</version>-->
<!--                <configuration>-->
<!--                    <source>1.8</source>-->
<!--                    <target>1.8</target>-->
<!--                    <encoding>UTF-8</encoding>-->
<!--                </configuration>-->
<!--            </plugin>-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>

        </plugins>

情况1 jar包内配置文件的修改

操作之前原来jar包先备份

解决办法1

linux服务中直接 vim mybatis-flex-springboot-1.0-SNAPSHOT.jar

一般配置文件在BOOT-INF/classes目录下、pom文件在META-INFO目录下

解决方法2

或者jar -xvf mybatis-flex-springboot-1.0-SNAPSHOT.jar

解压完毕后 进入对应的目录进行修改

修改完毕后重新压缩

例如我的示例jar包解压后有三个目录BOOT-INF、META-INFO、org

压缩命令:

js 复制代码
jar -cvfM0 mybatis-flex-springboot-1.0-SNAPSHOT.jar BOOT-INF/ META-INF/ org

压缩完验证下 java -jar mybatis-flex-springboot-1.0-SNAPSHOT.jar 看看包是否有问题

注:第三方依赖的jar包在BOOT-INF/lib下 如果需要修改也是先用jar -xvf解压 修改后 重新压成jar包,替换掉原来的lib目录下的jar包,然后返回上层再压出来最终的jar包,lib目录下解压生成的BOOT-INF、META-INFO在打包外层的jar包时要删掉 不然会报错

情况2 jar包内代码逻辑需要修改

向目标服务器传文件方便(本地有源码)

往目标服务器上传文件简单的话,本地可以编译的话,直接进行编译将编译完的class文件上传到服务器中,参考情况1中的第二种方法,将class文件上传到BOOT-INF/classes/具体的目录下,替换掉原来的class文件,并重新进行打包

向目标服务器传文件困难

arthas工具可反编译出代码,可以将修改的代码编译为class文件,并可利用redefine命令进行热更新。如果要使用redefine命令,对原来类的修改不能增加方法 也不能在方法中新增加参数,如果在类中修改涉及到新增方法或者在方法列表中增加参数,可以参考情况1.解决方法2 编译完成后 手动封装成jar包

redefine 的限制,详细参考下面链接
arthas.aliyun.com/doc/redefin...

使用 sc命令查看JVM已加载类信息

js 复制代码
sd -d demo.MathGame

最后一行的classLoaderHash的值 我们后续需要使用 反编译代码

javascript 复制代码
    jad -c 70dea4e --source-only demo.MathGame > /tmp/MathGame.java
  • jad命令是反编译指定已加载类的源码
  • -c : 类所属 ClassLoader 的 hashcode
  • --source-only:默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。
  • demo.MathGame:要反编译的类全路径

根据需要修改代码

编译代码

  • mc: 编译.java文件生.class文件, 详细使用方法参考官方文档arthas.aliyun.com/doc/mc.html
  • -c:指定classloader的hash值
  • -d:指定输出目录

最后将修改的class加载到jvm中

js 复制代码
redefine -c 70dea4e /tmp/MathGame.class

常见问题

arthas反编译.java文件时,可能会失败,可以使用javac命令进行编译 javac -cp参数可以指定编译依赖的jar包或者class文件 如果有多个路径的情况下,在window下 多个路径以";"分割开,linux下 以":"分隔开。

js 复制代码
#windows命令参数
javac -encoding UTF-8  -cp "D:\Users\fyzhang5\work\reference\learn\jarAddLibrary\lib\BOOT-INF\classes\;D:\Users\fyzhang5\work\reference\learn\jarAddLibrary\lib\BOOT-INF\lib\*" AccountController.java
js 复制代码
  #linux命令参数
    javac -encoding UTF-8  -cp "/tmp/mybatis-flex/BOOT-INF/classes/:/tmp/mybatis-flex/BOOT-INF/lib/*" AccountController.java

编译出来.class文件,参考情况1中的方式2 重新构建jar包镜像,步骤麻烦 但是凑合能用,比搞个包一弄大半天省点劲

参考文章

juejin.cn/post/705651...

相关推荐
汤姆yu3 分钟前
基于springboot的个人财务管理系统的设计与实现
java·spring boot·后端·个人财务管理
小鱼人爱编程4 分钟前
离职当晚,我删除了所有同事的微信
android·前端·后端
风象南19 分钟前
Redis缓存雪崩的5种应对措施
redis·后端
编程轨迹20 分钟前
四条建议:帮你构建健壮的 Java REST API
后端
橘猫云计算机设计30 分钟前
django基于爬虫的网络新闻分析系统的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
后端·爬虫·python·django·毕业设计·springboot
淬渊阁9 小时前
Hello world program of Go
开发语言·后端·golang
Pandaconda9 小时前
【新人系列】Golang 入门(十五):类型断言
开发语言·后端·面试·golang·go·断言·类型
周Echo周9 小时前
16、堆基础知识点和priority_queue的模拟实现
java·linux·c语言·开发语言·c++·后端·算法
魔道不误砍柴功10 小时前
Spring Boot自动配置原理深度解析:从条件注解到spring.factories
spring boot·后端·spring