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...

相关推荐
Moshow郑锴2 小时前
Spring Boot 3 + Undertow 服务器优化配置
服务器·spring boot·后端
Chandler243 小时前
Go语言即时通讯系统 开发日志day1
开发语言·后端·golang
有梦想的攻城狮3 小时前
spring中的@Lazy注解详解
java·后端·spring
野犬寒鸦3 小时前
Linux常用命令详解(下):打包压缩、文本编辑与查找命令
linux·运维·服务器·数据库·后端·github
huohuopro4 小时前
thinkphp模板文件缺失没有报错/thinkphp无法正常访问控制器
后端·thinkphp
cainiao0806057 小时前
《Spring Boot 4.0新特性深度解析》
java·spring boot·后端
-曾牛7 小时前
Spring AI 与 Hugging Face 深度集成:打造高效文本生成应用
java·人工智能·后端·spring·搜索引擎·springai·deepseek
南玖yy7 小时前
C/C++ 内存管理深度解析:从内存分布到实践应用(malloc和new,free和delete的对比与使用,定位 new )
c语言·开发语言·c++·笔记·后端·游戏引擎·课程设计
计算机学姐8 小时前
基于SpringBoot的小区停车位管理系统
java·vue.js·spring boot·后端·mysql·spring·maven
BUG制造机.8 小时前
Go 语言 slice(切片) 的使用
开发语言·后端·golang