1. 程式人生 > >java agent的簡單使用/基於java agent的完全無侵入的監控系統

java agent的簡單使用/基於java agent的完全無侵入的監控系統

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的欄位來獲取其引用。