激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - java.lang.Instrument 代理Agent使用詳細(xì)介紹

java.lang.Instrument 代理Agent使用詳細(xì)介紹

2020-07-08 14:09陶邦仁 Java教程

這篇文章主要介紹了java.lang.Instrument 代理Agent使用詳細(xì)介紹的相關(guān)資料,附有實(shí)例代碼,幫助大家學(xué)習(xí)參考,需要的朋友可以參考下

java.lang.Instrument 代理Agent使用

java.lang.Instrument包是在JDK5引入的,程序員通過修改方法的字節(jié)碼實(shí)現(xiàn)動(dòng)態(tài)修改類代碼。這通常是在類的main方法調(diào)用之前進(jìn)行預(yù)處理的操作,通過java指定該類的代理類來實(shí)現(xiàn)。在類的字節(jié)碼載入JVM前會(huì)調(diào)用ClassFileTransformer的transform方法,從而實(shí)現(xiàn)修改原類方法的功能,實(shí)現(xiàn)AOP,這個(gè)的好處是不會(huì)像動(dòng)態(tài)代理或者CGLIB技術(shù)實(shí)現(xiàn)AOP那樣會(huì)產(chǎn)生一個(gè)新類,也不需要原類要有接口。

(1) 代理 (agent) 是在你的main方法前的一個(gè)攔截器 (interceptor),也就是在main方法執(zhí)行之前,執(zhí)行agent的代碼。 agent的代碼與你的main方法在同一個(gè)JVM中運(yùn)行,并被同一個(gè)system classloader裝載,被同一的安全策略 (security policy)和上下文 (context)所管理。 代理(agent)這個(gè)名字有點(diǎn)誤導(dǎo)的成分,它與我們一般理解的代理不大一樣。java agent使用起來比較簡(jiǎn)單。怎樣寫一個(gè)java agent? 只需要實(shí)現(xiàn)premain這個(gè)方法: public static void premain(String agentArgs, Instrumentation inst) JDK 6 中如果找不到上面的這種premain的定義,還會(huì)嘗試調(diào)用下面的這種premain定義: public static void premain(String agentArgs)

(2)Agent 類必須打成jar包,然后里面的META-INF/MAINIFEST.MF,必須包含Premain-Class這個(gè)屬性。 下面是一個(gè)MANIFEST.MF的例子:

Manifest-Version: 1.0 Premain-Class:MyAgent1 Created-By:1.6.0_06

然后把MANIFEST.MF加入到你的jar包中。以下是agent jar文件的Manifest Attributes清單: Premain-Class 如果 JVM 啟動(dòng)時(shí)指定了代理,那么此屬性指定代理類,即包含 premain 方法的類。如果 JVM 啟動(dòng)時(shí)指定了代理,那么此屬性是必需的。如果該屬性不存在,那么 JVM 將中止。注:此屬性是類名,不是文件名或路徑。 Agent-Class 如果實(shí)現(xiàn)支持 VM 啟動(dòng)之后某一時(shí)刻啟動(dòng)代理的機(jī)制,那么此屬性指定代理類。 即包含 agentmain 方法的類。 此屬性是必需的,如果不存在,代理將無法啟動(dòng)。注:這是類名,而不是文件名或路徑。 Boot-Class-Path 設(shè)置引導(dǎo)類加載器搜索的路徑列表。路徑表示目錄或庫(kù)(在許多平臺(tái)上通常作為 JAR 或 zip 庫(kù)被引用)。查找類的特定于平臺(tái)的機(jī)制失敗后,引導(dǎo)類加載器會(huì)搜索這些路徑。按列出的順序搜索路徑。列表中的路徑由一個(gè)或多個(gè)空格分開。路徑使用分層 URI 的路徑組件語(yǔ)法。如果該路徑以斜杠字符(“/”)開頭,則為絕對(duì)路徑,否則為相對(duì)路徑。相對(duì)路徑根據(jù)代理 JAR 文件的絕對(duì)路徑解析。忽略格式不正確的路徑和不存在的路徑。如果代理是在 VM 啟動(dòng)之后某一時(shí)刻啟動(dòng)的,則忽略不表示 JAR 文件的路徑。此屬性是可選的。 Can-Redefine-Classes 布爾值(true 或 false,與大小寫無關(guān))。是否能重定義此代理所需的類。true 以外的值均被視為 false。此屬性是可選的,默認(rèn)值為 false。 Can-Retransform-Classes 布爾值(true 或 false,與大小寫無關(guān))。是否能重轉(zhuǎn)換此代理所需的類。true 以外的值均被視為 false。此屬性是可選的,默認(rèn)值為 false。 Can-Set-Native-Method-Prefix 布爾值(true 或 false,與大小寫無關(guān))。是否能設(shè)置此代理所需的本機(jī)方法前綴。true 以外的值均被視為 false。此屬性是可選的,默認(rèn)值為 false。

(3)所有的這些Agent的jar包,都會(huì)自動(dòng)加入到程序的classpath中。所以不需要手動(dòng)把他們添加到classpath。除非你想指定classpath的順序。

(4)一個(gè)java程序中-javaagent這個(gè)參數(shù)的個(gè)數(shù)是沒有限制的,所以可以添加任意多個(gè)java agent。所有的java agent會(huì)按照你定義的順序執(zhí)行。 例如:

java -javaagent:MyAgent1.jar -javaagent:MyAgent2.jar -jar MyProgram.jar

假設(shè)MyProgram.jar里面的main函數(shù)在MyProgram中。MyAgent1.jar, MyAgent2.jar, 這2個(gè)jar包中實(shí)現(xiàn)了premain的類分別是MyAgent1, MyAgent2 程序執(zhí)行的順序?qū)?huì)是:

MyAgent1.premain -> MyAgent2.premain -> MyProgram.main

(5)另外,放在main函數(shù)之后的premain是不會(huì)被執(zhí)行的,例如:

java -javaagent:MyAgent1.jar -jar MyProgram.jar -javaagent:MyAgent2.jar

MyAgent2 都放在了MyProgram.jar后面,所以MyAgent2的premain都不會(huì)被執(zhí)行,所以執(zhí)行的結(jié)果將是:

MyAgent1.premain -> MyProgram.main

(6)每一個(gè)java agent 都可以接收一個(gè)字符串類型的參數(shù),也就是premain中的agentArgs,這個(gè)agentArgs是通過java option中定義的。例如:

java -javaagent:MyAgent2.jar=thisIsAgentArgs -jar MyProgram.jar

MyAgent2中premain接收到的agentArgs的值將是”thisIsAgentArgs” (不包括雙引號(hào))。

(7)參數(shù)中的Instrumentation:通過參數(shù)中的Instrumentation inst,添加自己定義的ClassFileTransformer,來改變class文件。這里自定義的Transformer實(shí)現(xiàn)了transform方法,在該方法中提供了對(duì)實(shí)際要執(zhí)行的類的字節(jié)碼的修改,甚至可以達(dá)到執(zhí)行另外的類方法的地步。例如: 寫agent類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.toy;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
public class PerfMonAgent {
  private static Instrumentation inst = null;
  /**
   * This method is called before the application's main-method is called,
   * when this agent is specified to the Java VM.
   **/
  public static void premain(String agentArgs, Instrumentation _inst) {
    System.out.println("PerfMonAgent.premain() was called.");
    // Initialize the static variables we use to track information.
    inst = _inst;
    // Set up the class-file transformer.
    ClassFileTransformer trans = new PerfMonXformer();
    System.out.println("Adding a PerfMonXformer instance to the JVM.");
    inst.addTransformer(trans);
  }
}

寫ClassFileTransformer類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.toy;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
public class PerfMonXformer implements ClassFileTransformer {
  public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    byte[] transformed = null;
    System.out.println("Transforming " + className);
    ClassPool pool = ClassPool.getDefault();
    CtClass cl = null;
    try {
      cl = pool.makeClass(new java.io.ByteArrayInputStream(
          classfileBuffer));
      if (cl.isInterface() == false) {
        CtBehavior[] methods = cl.getDeclaredBehaviors();
        for (int i = 0; i < methods.length; i++) {
          if (methods[i].isEmpty() == false) {
            doMethod(methods[i]);
          }
        }
        transformed = cl.toBytecode();
      }
    } catch (Exception e) {
      System.err.println("Could not instrument " + className
          + ", exception : " + e.getMessage());
    } finally {
      if (cl != null) {
        cl.detach();
      }
    }
    return transformed;
  }
  private void doMethod(CtBehavior method) throws NotFoundException,
      CannotCompileException {
    // method.insertBefore("long stime = System.nanoTime();");
    // method.insertAfter("System.out.println(\"leave "+method.getName()+" and time:\"+(System.nanoTime()-stime));");
    method.instrument(new ExprEditor() {
      public void edit(MethodCall m) throws CannotCompileException {
        m.replace("{ long stime = System.nanoTime(); $_ = $proceed($$); System.out.println(\""
                + m.getClassName()+"."+m.getMethodName()
                + ":\"+(System.nanoTime()-stime));}");
      }
    });
  }
}

上面兩個(gè)類就是agent的核心了,jvm啟動(dòng)時(shí)并會(huì)在應(yīng)用加載前會(huì)調(diào)用 PerfMonAgent.premain,然后PerfMonAgent.premain中實(shí)例化了一個(gè)定制的ClassFileTransforme即 PerfMonXformer,并通過inst.addTransformer(trans);把PerfMonXformer的實(shí)例加入Instrumentation實(shí)例(由jvm傳入),這就使得應(yīng)用中的類加載的時(shí)候, PerfMonXformer.transform都會(huì)被調(diào)用,你在此方法中可以改變加載的類,真的有點(diǎn)神奇,為了改變類的字節(jié)碼,我使用了jboss的javassist,雖然你不一定要這么用,但jboss的javassist真的很強(qiáng)大,讓你很容易的改變類的字節(jié)碼。

在上面的方法中我通過改變類的字節(jié)碼,在每個(gè)類的方法入口中加入了long stime = System.nanoTime();,在方法的出口加入了System.out.println(“methodClassName.methodName:”+(System.nanoTime()-stime));

 感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

原文鏈接:https://my.oschina.net/xianggao/blog/362495

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 中文字幕精品在线播放 | 黄色片免费在线播放 | 九九热精品免费 | 国产91porn | 国产99一区二区 | 国产成人免费高清激情视频 | 中国毛片在线观看 | 久久99国产精品免费网站 | 久久久免费观看完整版 | 亚洲影院在线播放 | 看免费av | 激情视频免费观看 | 日韩在线激情 | 日本免费一区二区三区四区 | 国产一区二区午夜 | 蜜桃视频观看麻豆 | 中文在线观看视频 | 男女视频免费看 | 久久生活片 | 九九精品在线 | 99精品视频在线导航 | 国产视频精品在线 | 蜜桃视频在线观看视频 | 羞羞视频免费观看入口 | 91av视频大全 | 国产孕妇孕交大片孕 | 久久手机在线视频 | 青青青在线免费 | 日本一区视频在线观看 | 中文字幕国产亚洲 | 中国大陆一级毛片 | 一级毛片免费高清视频 | 国产精品99久久久久久董美香 | 亚洲午夜久久久精品一区二区三区 | 污片视频网站 | 亚洲精品久久久久久久久久久 | 成人福利免费在线观看 | 国产91一区 | 在线播放免费视频 | 精品一区二区三区在线观看国产 | 羞羞的视频免费 |