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-INFMETA-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.javajavassist.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 代码中的字符串常量。

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


本文配套资源下载

相关推荐
木白CPP12 小时前
Linux DMA驱动详解(二)-----DMA的使用者
java·linux·运维
caoerzhong12 小时前
JeeWMS 开源仓库管理系统 GPL-3.0 合规指南:Java WMS 二次开发前必须弄清的授权边界
java·开发语言·开源·vue
Sam_Deep_Thinking12 小时前
单一职责原则:JAVA LocalDate的设计取舍
java·后端·程序员·单一职责原则
杨杨杨大侠12 小时前
Java 不再需要 JVM?一文看懂 GraalVM Native Image、Substrate VM 与 JDK
java·jvm·java ee
Sylvia33.13 小时前
火星数据体育API|一站式接入足球篮球电竞等18+项目实时数据
java·开发语言·python·websocket·游戏
李少兄13 小时前
解决 MySQL Lock wait timeout exceeded 报错
java
va学弟13 小时前
Java 语言特性:泛型(Generics)
java·泛型
SL_staff13 小时前
插单风险的数据闭环治理:JVS-BI 在制造业实时预警中的技术实践
java·数据分析·数据可视化
白远山14 小时前
健身场馆无人自动化解决方案:从架构到落地实践
java·开发语言·数据库·数据挖掘·需求分析
user_admin_god14 小时前
第 01 篇:OpenAI 兼容 API 初探 —— 用 curl 跑通第一次对话
java·人工智能·spring boot·语言模型·devops