基础准备
现在,我们需要一个程序入口,随时挂接具体的java应用和刚刚开发的agent。
首先,我们考虑java自身提供的功能:监控能力,主要包在 sun.jvmstat下,可以拿到当时正在运行的所有java进程,如此便可以让系统自动找到我们的测试java应用,避免每次去查看系统的进程号。
其次,我们考虑怎么动态的加载agent,目前来说最好的方式有两种,一个是自己引用tools.jar,使用类
com.sun.tools.attach.VirtualMachine加载,另外一种,就是借助第三方工具类,比如bytebuddy,目前我们先采用方式一,后面我们会详细讲解方式二。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jvm_sandbox_demo</artifactId>
<groupId>com.deer</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.deer.agent.starter</groupId>
<artifactId>jvm_sandbox_agent_starter</artifactId>
<name>jvm_sandbox_agent_starter</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>/Users/yudongwei/Library/Java/JavaVirtualMachines/corretto-1.8.0_322/Contents/Home/lib/tools.jar</systemPath>
</dependency>
</dependencies>
</project>
package com.deer.agent.starter;
import com.sun.tools.attach.VirtualMachine;
import sun.jvmstat.monitor.*;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
public class AgentStarter {
public static void main(String[] args) throws URISyntaxException, MonitorException {
String processId = null;
// 获取监控主机
MonitoredHost local = MonitoredHost.getMonitoredHost("localhost");
// 取得所有在活动的虚拟机集合
Set<Integer> vmlist = new HashSet<Integer>(local.activeVms());
// 遍历集合,找到我们系统启动需要挂载的PID和进程名
for(Integer process : vmlist) {
MonitoredVm vm = local.getMonitoredVm(new VmIdentifier("//" + process));
// 获取类名
String processName = MonitoredVmUtil.mainClass(vm, true);
if(processName.equals("com.deer.base.BaseApp")){
processId = process.toString();
break;
}
}
if(processId == null){
return;
}
System.out.println("find processId ,and ready to attach..."+processId);
String agentPath="/Users/yudongwei/IdeaProjects/jvm_sandbox_demo/jvm_sandbox_agent/target/jvm_sandbox_agent-1.0-SNAPSHOT-jar-with-dependencies.jar";
try {
VirtualMachine vm = VirtualMachine.attach(processId);
vm.loadAgent(agentPath);
}catch (Exception e){
e.printStackTrace();
}
}
}
测试效果
启动 spring 应用:com.deer.base.BaseApp
打包agent
启动入口:com.deer.agent.starter.AgentStarter
基础测试
功能测试
我们用浏览器访问
http://localhost:9090/sayHi/zhangfei
新的问题
此时我们发现,自己定义的类有一个被agent访问到了(com.deer.base.service.BaseService),另外一个没有被agent访问到(com.deer.base.service.impl.HelloServiceImpl)
是我们代码写错了,还是另有玄机?
是不是因为spring的bean使用java代理,此时类名已经不匹配了?
这些都会随着接下来的课程一步一步抽丝剥茧解决。