
本文介绍一种不侵入应用代码、不重启服务的前提下,通过 java attach api 动态修改运行中 jvm 系统属性的方法,适用于应用服务器环境下的调试与配置热更新。
本文介绍一种不侵入应用代码、不重启服务的前提下,通过 java attach api 动态修改运行中 jvm 系统属性的方法,适用于应用服务器环境下的调试与配置热更新。
在生产环境中,有时需要临时调整 JVM 的系统属性(如 user.timezone、com.sun.management.jmxremote 相关参数,或自定义业务开关),但又无法停机、不能修改源码、也无法重新配置启动参数(如 -D)。此时,Java 提供的 Attach API 与 Java Agent 机制 可以完美解决这一需求:通过外部工具将一个轻量级 agent 动态注入正在运行的 JVM 进程,并在 agentmain 中安全调用 System.setProperty() 完成属性变更。
✅ 核心原理
JVM 支持运行时附加(attach)Java Agent,该 agent 无需在启动时加载(即不依赖 -javaagent),而是通过 com.sun.tools.attach.VirtualMachine 类连接目标进程(需同一用户权限且 JVM 启用了 attach 功能),再加载并执行 agentmain 方法。此过程完全独立于目标应用逻辑,零代码侵入。
?️ 实现步骤(以 JDK 11+ 为例)
1. 编写 Agent 主类(SetProperty.java)
import com.sun.tools.attach.VirtualMachine;
public class SetProperty {
public static void main(String[] args) throws Exception {
String url = SetProperty.class.getProtectionDomain().getCodeSource().getLocation().toString();
if (args.length <key>");
System.exit(1);
}
VirtualMachine vm = VirtualMachine.attach(args[0]);
try {
int startIndex = "\".equals(System.getProperty("file.separator")) ? 6 : 5;
vm.loadAgent(url.substring(startIndex), args[1]);
} finally {
vm.detach();
}
}
public static void agentmain(String args) {
int eq = args.indexOf('=');
if (eq == -1) {
throw new IllegalArgumentException("Invalid format: expected 'key=value'");
}
String key = args.substring(0, eq).trim();
String value = args.substring(eq + 1).trim();
System.setProperty(key, value);
System.out.println("[✓] Set system property: " + key + "=" + value);
}
}</key>
⚠️ 注意:
agentmain在目标 JVM 的上下文中执行,因此System.setProperty()生效范围为整个 JVM —— 所有后续System.getProperty()调用均可读取新值(但已缓存该属性的类,如TimeZone.getDefault(),可能需额外刷新逻辑)。
2. 构建可执行 Agent JAR
创建 MANIFEST.MF:
Main-Class: SetProperty Agent-Class: SetProperty
打包命令:
javac -source 8 -target 8 SetProperty.java jar cfm setproperty.jar MANIFEST.MF SetProperty.class
3. 运行注入命令
# 查找目标 Java 进程 PID(例如 Tomcat、Spring Boot 应用) jps -l # 注入属性(JDK 9+ 直接运行 JAR) java -jar setproperty.jar 12345 my.custom.flag=true # JDK 8 需显式引入 tools.jar java -cp setproperty.jar:$JAVA_HOME/lib/tools.jar SetProperty 12345 my.custom.flag=true
✅ 成功执行后,目标 JVM 即刻生效新属性。可通过 JMX 控制台、jcmd 或应用内日志验证。
? 补充说明与注意事项
-
权限要求:运行
setproperty.jar的用户必须与目标 JVM 进程属同一用户(Linux/macOS 下因/tmp/.java_pid*文件权限限制);Windows 下通常无此限制。 -
JDK 兼容性:JDK 9+ 默认支持 Attach API;JDK 8 需确保
tools.jar在 classpath;JDK 17+(无默认tools.jar)仍支持VirtualMachine(已移入jdk.attach模块,无需额外配置)。 -
线程安全性:
System.setProperty()是线程安全的,但若多个 agent 并发修改同一属性,结果取决于执行顺序。 -
局限性:无法修改
final系统属性(如java.version、os.name);部分框架(如 Spring Boot)会在启动时快照系统属性,后续修改对其自动配置无效 —— 此时需结合框架特定机制(如@RefreshScope)或重启相关 Bean。 -
生产建议:仅用于运维调试或紧急配置切换;长期配置应通过标准方式(
-D、配置中心、环境变量)管理,避免运行时状态漂移。
? 小技巧:已预编译的 setproperty.jar 可直接下载使用,跳过编译步骤。
通过该方案,你获得了对 JVM 运行时配置的精细控制能力——无需重启、不改代码、不依赖应用层支持,真正实现“热插拔式”系统属性管理。










