Spring Boot Jar包修改配置文件和Class中硬编码IP的完整指南

前言

在实际开发中,我们有时会遇到这样的情况:从第三方或历史版本中拿到一个 Spring Boot 打好的 jar 包,但里面某个服务的 IP 地址是写死的(无论是在 application.yml 还是直接在 Java 代码中作为字符串常量)。由于无法获取源码或重新编译,我们需要一种直接修改 jar 包的方法来替换 IP。

本文将以一个真实场景为例,详细介绍如何不借助源码 ,直接修改 Spring Boot fat jar 中的 application.yml 配置文件和 .class 字节码中的硬编码 IP,并重新打包成可运行的 jar。


问题背景

有一个 Spring Boot 项目编译后的 collector.jar,内部包含:

  • BOOT-INF/classes/application.yml ------ 配置文件中写死了旧 IP 192.168.1.100

  • BOOT-INF/classes/com/xcr/socket/CollectorApplication.class ------ 字节码中硬编码了 IP xxx.175.167.44

现在需要将这两处 IP 都改为新的 10.0.0.5,并且保证修改后的 jar 能正常启动。


解决思路

类型 修改方法 工具
配置文件 application.yml 文本替换 文本编辑器 / PowerShell
.class 中的硬编码字符串 字节码修改(替换常量池) Javassist

为什么不用反编译再重新编译?因为反编译后的代码可能不完整,且重新编译需要完整的依赖和环境,很容易失败。直接操作字节码更安全可靠。


环境准备


操作步骤

1. 解压 jar 包

复制代码
jar xf collector.jar

解压后会出现 BOOT-INF 和 META-INF 等目录。BOOT-INF/classes 下就是项目的 class 文件和配置文件。

2. 修改 application.yml

直接用文本编辑器(如 VS Code, Notepad++)打开:

复制代码
BOOT-INF/classes/application.yml

将其中所有的 192.168.1.100 替换为 10.0.0.5,保存。

3. 修改 CollectorApplication.class 中的硬编码 IP

这里不使用反编译,而是直接用 Javassist 操作字节码。核心原理:找到所有 ldc 指令(加载字符串常量),检查其指向的常量池条目是否为旧 IP,若是则修改常量池索引,使其指向新 IP 字符串。

新建 FixIPBytecode.java(完整代码如下):

java 复制代码
import javassist.*;
import javassist.bytecode.*;

public class FixIPBytecode {
    public static void main(String[] args) throws Exception {
        // TODO: 修改为你的旧IP和新IP
        String oldIp = "xxx.175.167.44";
        String newIp = "10.0.0.5";

        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath("BOOT-INF/classes/");
        CtClass ctClass = pool.get("com.xcr.socket.CollectorApplication");

        CtMethod[] methods = ctClass.getDeclaredMethods();
        for (CtMethod method : methods) {
            MethodInfo methodInfo = method.getMethodInfo();
            CodeAttribute codeAttr = methodInfo.getCodeAttribute();
            if (codeAttr == null) continue;

            CodeIterator iterator = codeAttr.iterator();
            ConstPool constPool = methodInfo.getConstPool();

            while (iterator.hasNext()) {
                int index = iterator.next();
                int op = iterator.byteAt(index);
                
                // 0x12 是 ldc 的操作码(加载常量)
                if (op == Opcode.LDC) {
                    int constPoolIndex = iterator.byteAt(index + 1);
                    if (constPool.getTag(constPoolIndex) == ConstPool.CONST_String) {
                        String currentStr = constPool.getStringInfo(constPoolIndex);
                        if (oldIp.equals(currentStr)) {
                            int newConstPoolIndex = constPool.addStringInfo(newIp);
                            iterator.writeByte(newConstPoolIndex & 0xff, index + 1);
                            System.out.println("在方法 " + method.getName() + " 中找到并替换常量: " + oldIp + " -> " + newIp);
                        }
                    }
                }
            }
        }
        ctClass.writeFile("BOOT-INF/classes/");
        ctClass.detach();
        System.out.println("Class 文件修改完成。");
    }
}

编译并运行:

复制代码
javac -cp ".;javassist.jar" FixIPBytecode.java
java -cp ".;javassist.jar" FixIPBytecode

执行后控制台输出类似:

复制代码
在方法 main 中找到并替换常量: xxx.175.167.44 -> 10.0.0.5
Class 文件修改完成。

此时 BOOT-INF/classes/com/xcr/socket/CollectorApplication.class 已被修改。

4. 将修改后的文件更新回 jar 包

注意 :不要重新打包整个 jar(即不要用 jar cf),那样会破坏 Spring Boot 的启动信息。而是用 jar uf 只替换修改过的文件:

复制代码
jar uf collector.jar BOOT-INF/classes/application.yml
jar uf collector.jar BOOT-INF/classes/com/xcr/socket/CollectorApplication.class

5. 清理临时目录并测试

复制代码
# 删除解压出的目录
rmdir /s /q BOOT-INF META-INF org

# 运行修改后的 jar
java -jar collector.jar

观察日志,确认新 IP 已生效。


一键脚本(Windows .bat)

为了方便,可以将上述步骤整合成一个批处理脚本 fix_ip.bat:

复制代码
@echo off
echo 1. 解压JAR...
jar xf collector.jar

echo 2. 修改application.yml...
powershell -Command "(Get-Content BOOT-INF\classes\application.yml) -replace '192.168.1.100', '10.0.0.5' | Set-Content BOOT-INF\classes\application.yml"

echo 3. 编译并运行Javassist修改class...
javac -cp ".;javassist.jar" FixIPBytecode.java
java -cp ".;javassist.jar" FixIPBytecode

echo 4. 更新JAR包...
jar uf collector.jar BOOT-INF/classes/application.yml
jar uf collector.jar BOOT-INF/classes/com/xcr/socket/CollectorApplication.class

echo 5. 清理临时目录...
rmdir /s /q BOOT-INF META-INF org 2>nul

echo 完成!新jar已生成:collector.jar
pause

将 FixIPBytecode.java 和 javassist.jar 放在同一目录,双击运行 fix_ip.bat 即可。


常见问题与排错

Q1: 运行 javac 时提示"找不到符号 ExprEditor / StringConst"

这是因为之前网上有些教程使用了错误的类名。本文提供的 FixIPBytecode.java 直接操作常量池和字节码,不依赖那些不存在的类,可以避免此问题。

Q2: 运行 java 时提示"ClassNotFoundException: javassist.ClassPool"

请检查 classpath 是否包含 javassist.jar,且写法正确(Windows 用分号分隔,当前目录用 . 表示)。正确命令:

bash

复制代码
java -cp ".;javassist.jar" FixIPBytecode

Q3: Javassist 没有找到要替换的 IP 字符串

先用 javap 确认 class 文件中确实存在该字符串:

bash

复制代码
javap -v BOOT-INF/classes/com/xcr/socket/CollectorApplication.class | findstr "xxx.175.167.44"

如果能看到类似 #7 = String ... 的输出,说明字符串存在于常量池。我们的脚本通过遍历所有 ldc 指令来匹配,通常都能找到。

Q4: 修改后 jar 无法启动,提示"找不到主类"

一定不要使用 jar cf 重新打包整个目录。必须使用 jar uf 只替换个别文件,才能保留原 jar 中的 META-INF/MANIFEST.MF 和 Spring Boot 的启动类索引。

Q5: PowerShell 替换 YAML 时格式错乱

简单替换偶尔会改变文件编码或换行符。如果担心,可以手动编辑 application.yml 或用专业文本编辑器替换。脚本中的 PowerShell 命令对于普通字符串替换是安全的。


总结

通过本文的方法,你可以无需源码、无需反编译,直接修改 Spring Boot fat jar 中的配置文件和字节码中的硬编码字符串。核心思路是:

  1. 用 jar xf 解压。

  2. 直接编辑文本配置文件。

  3. 使用 Javassist 操作字节码常量池,替换 ldc 指令的目标字符串。

  4. 用 jar uf 增量更新回原 jar。

该方法适用于修改 IP 地址、数据库连接字符串、密钥等任何硬编码在 Java 代码中的字符串常量。

希望这篇教程能帮你解决实际问题。如果你有其他修改场景(比如修改数字常量、修改方法调用等),也可以在评论区留言交流。


本文配套资源下载:

相关推荐
paopaokaka_luck39 分钟前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
Thomas.Sir40 分钟前
第9课:SpringBoot4.x Web开发基础:WebMvc自动配置、静态资源、请求参数接收
java·spring boot
程序 代码狂人1 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
2501_944521592 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
南归北隐3 小时前
Spring AI Alibaba Graph框架实现MCP数据库查询实战
java·后端·spring ai·mcp·spring ai mcp
古法老登瞎折腾3 小时前
大数据智能运维实战(九):让 AI 查日志——找到异常,也保留上下文
java·大数据·运维·人工智能·spring ai·mcp
ai大模型-探索者3 小时前
Function Call与MCP(区别、联系与实战)
java·服务器·网络
略略略咯咯3 小时前
啊啊啊啊啊
java·服务器·数据库
SL_staff4 小时前
运维救火实战:钉钉API变更致薪资计算中断,如何用可视化逻辑引擎5分钟热修复
java·开源·全栈
猫猫.1534 小时前
HashTable、HashMap、ConcurrentHashMap 核心区别总结
java·开发语言·java-ee