JAVA AGENT的基本使用
本片文章将给出一个完全无侵入的使用java agent的进行业务监控的简单实例。
先来看一个网上的例子。https://blog.csdn.net/catoop/article/details/51034739
package com.shanhy.demo.agent;
import java.lang.instrument.Instrumentation;
/**
* 我的Java代理
*
* @author 单红宇(365384722)
* @myblog http://blog.csdn.net/catoop/
* @create 2016年3月30日
*/
public class MyAgent {
/**
* 该方法在main方法之前运行,与main方法运行在同一个JVM中
* 并被同一个System ClassLoader装载
* 被统一的安全策略(security policy)和上下文(context)管理
*
* @param agentOps
* @param inst
* @author SHANHY
* @create 2016年3月30日
*/
public static void premain(String agentOps, Instrumentation inst) {
System.out.println("=========premain方法执行========");
System.out.println(agentOps);
}
/**
* 如果不存在 premain(String agentOps, Instrumentation inst)
* 则会执行 premain(String agentOps)
*
* @param agentOps
* @author SHANHY
* @create 2016年3月30日
*/
public static void premain(String agentOps) {
System.out.println("=========premain方法执行2========");
System.out.println(agentOps);
}
}
修改MANIFEST文件后
以如下命令启动
java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.ja
上述代码是采用在JVM启动时加载java agent的。但是我们
被监控代码
一个简单的JAVA类,没有任何复杂处理
public class Main {
private static Integer count = 10;
public static void main(String[] args) {
System.out.println("begin");
while (true){
try {
count ++;
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
注入Agent的代码
import com.sun.tools.attach.VirtualMachine;
public class AgentMain
{
public static void main(String[] args) throws Exception
{
VirtualMachine vm = null;
String agentjarpath = "/Users/gdl/Desktop/java_pro/JavaAgentDemo/target/JavaAgentDemo-1.0-SNAPSHOT.jar"; //agentjar路径
vm = VirtualMachine.attach("96089");//JVM的PID
vm.loadAgent(agentjarpath, "This is Args to the Agent.");
vm.detach();
}
}
监控代码
public class Agent
{
public static void agentmain(String args, Instrumentation inst) throws Exception
{
System.out.println("Args:" + args);
System.out.println("Args2:" + args);
//下面检查监控
System.out.println(inst.getAllLoadedClasses().toString());
for (Class cls: inst.getAllLoadedClasses()
) {
//System.out.println(cls.getName());
if(cls.getName().equals("Main")){
Field f = cls.getDeclaredField("count");
f.setAccessible(true);
Object obj = f.get(null);
Integer count = (Integer)obj;
System.out.println(count.toString());
}
}
}
}
请在pom中添加如下内容来修改MANIFEST文件的内容,使JVM能识别该JAR包
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Built-By>gdl</Built-By>
<Agent-Class>com.gdl.Agent</Agent-Class>
<Class-Path>tools.jar</Class-Path>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
如何监控一个对象的字段?
显然,上面的例子只能应用于监控一个类的静态字段。这点是不够的。我们希望监控任意一个对象的字段。但是,对象的字段取出来并不难,如何获取指定对象的引用是一个大问题。这里,我们没有什么好办法,只能采取一个用static的字段来获取其引用。