java agent的簡單使用/基於java agent的完全無侵入的監控系統
阿新 • • 發佈:2018-12-04
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的欄位來獲取其引用。