前言
经常在应用的启动或者运行过程中需要动态的查看数据,或者实时的验证我们写的代码的结构与执行过程,此时需要一种工具能够动态的检测程序运行的状态,内存数据,线程情况,最好能够动态的替换代码实时生效,方便我们从日志或者其他埋点断言我们的猜测。
1. arthas 阿尔萨斯的工程结构
其实有很多工具可以达到这种效果,arthas就是其中一种。
从工程结构,其实arthas的核心功能是core,里面有arthas的attach与诊断指令的代码。 通过实际启动分析进一步看原理。
2. arthas 启动
2.1 打包
对源码去除
git-commit-id-plugin
插件,毕竟现在github已经很难连接了
执行mvn clean package,在packing module下
src下面其实有
assembly.xml
文件定义了打包的详情,每个module定义了打包的插件,毕竟诊断工具需要把所有第三方的jar class字节码打进jar,即fatjar,所以对依赖需要尽量少,观源码arthas重度依赖Telnet netty,感觉依赖有点重。
2.2 执行boot启动
boot的启动是执行java -jar,其实就是一个普通的jar应用
2.2.1 选择进程pid
pid = ProcessUtils.select(bootstrap.isVerbose(), telnetPortPid, bootstrap.getSelect());
其实很简单,就是去找java home,找到jps命令,然后jps -l
可以看到findJps
查找本机jvm进程
2.2.2 启动进程attach pid
ProcessUtils.startArthasCore(pid, attachArgs);
不明白为啥要独立启动一个进程去attach,这个进程在attach完成后自动运行结束。参数就是前面的pid core agent等,其实核心是pid agent jar,其他都是额外功能的。
public static void startArthasCore(long targetPid, List<String> attachArgs) {
// find java/java.exe, then try to find tools.jar
String javaHome = findJavaHome();
// find java/java.exe
File javaPath = findJava(javaHome);
if (javaPath == null) {
throw new IllegalArgumentException(
"Can not find java/java.exe executable file under java home: " + javaHome);
}
File toolsJar = findToolsJar(javaHome);
if (JavaVersionUtils.isLessThanJava9()) {
if (toolsJar == null || !toolsJar.exists()) {
throw new IllegalArgumentException("Can not find tools.jar under java home: " + javaHome);
}
}
List<String> command = new ArrayList<String>();
command.add(javaPath.getAbsolutePath());
if (toolsJar != null && toolsJar.exists()) {
command.add("-Xbootclasspath/a:" + toolsJar.getAbsolutePath());
}
command.addAll(attachArgs);
// "${JAVA_HOME}"/bin/java \
// ${opts} \
// -jar "${arthas_lib_dir}/arthas-core.jar" \
// -pid ${TARGET_PID} \
// -target-ip ${TARGET_IP} \
// -telnet-port ${TELNET_PORT} \
// -http-port ${HTTP_PORT} \
// -core "${arthas_lib_dir}/arthas-core.jar" \
// -agent "${arthas_lib_dir}/arthas-agent.jar"
ProcessBuilder