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

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java Agent 動態修改字節碼詳情

Java Agent 動態修改字節碼詳情

2021-12-23 13:14老K的Java博客 Java教程

這篇文章主要介紹了Java Agent動態修改字節碼的相關資料,需要的朋友可以參考下面文章具體的內容

Java Agent 動態修改字節碼詳情

假設您有一個在生產環境中運行的應用程序。每隔一段時間,它就會進入中斷狀態,錯誤很難重現,您需要從應用程序中獲得更多信息。

那么你想知道解決方案嗎?

您可以做的是動態地將一些代碼集附加到應用程序中,并仔細地重寫它,以便代碼轉儲您可以記錄的其他信息,或者您可以將應用程序階段轉儲到文本文件中。Java為我們提供了使用Java Agent實現這一點的工具。

你有沒有想過我們的Java代碼是如何在IDE中進行熱交換的?這是因為特工。關于Java Agent的另一個有趣的事實是,應用程序探查器在后端使用相同的技術來收集內存使用情況、內存泄漏和方法執行時間的信息。

 

1、什么是Java Agent

Java Agent是一種特殊類型的類,通過使用Java Instrumentation API,它可以攔截JVM上運行的應用程序,修改它們的字節碼。Java Agent非常強大,也非常危險。

在開始之前,我將解釋Java Agent如何使用簡單的HelloWorld示例攔截類。

public class Hello {
  public static void main(String[] args){
      System.out.println("hello world");
  }
}


如下圖所示:

Java Agent 動態修改字節碼詳情

類加載器負責將類從二進制加載到內存中。運行編譯后的HelloWorld應用程序(HelloWorld.class)時,可以將Agent視為在運行時攔截類加載器行為的一種方式。您可能會想,java字節代碼是如何被重新構造的,以便Agent可以在正確的位置添加相關代碼的。有趣的是,對于Java程序來說,字節碼的結構非常接近原始Java程序源代碼。因此,雖然我們不為Java程序本身添加工具,但我們使用了它的一個非常接近的表示形式。需要注意的是,有一些非Java語言可以編譯成Java字節碼(如Scala、Clojure和Kotlin),這意味著程序字節碼的結構和形狀可能會非常不同。

 

2、實現Java Agent

JavaAgent基于來自Java平臺的facility,它的入口點是Java.lang instrument包,它提供了允許Agent為JVM上運行的程序提供工具的服務。該包非常簡單且自包含,因為它包含兩個異常類、一個數據類、類定義和兩個接口。在這兩種方法中,如果我們想編寫Java Agent,我們只需要實現classFileTransformer接口。

定義代理有兩種方法。

第一個是靜態代理,這意味著我們構建Agent代理,將其打包為jar文件,當我們啟動Java應用程序時,我們傳入一個名為java agent的特殊JVM參數。然后我們給它代理jar在磁盤上的位置,然后JVM發揮它的魔力。

$ java -javaagent:<path of agent jar file> -jar <path of the packaged jar file you want to intecept>


我們需要添加一個特殊的清單條目,稱為pre-main類,當然,這是一個完全限定的名稱類定義。

Premain-Class : org.example.JavaAgent


這個類看起來像這樣

public class JavaAgent {
  /**
   * As soon as the JVM initializes, This  method will be called.
   *
   * @param agentArgs       The list of agent arguments
   * @param instrumentation The instrumentation object
   * @throws InstantiationException
   */
  public static void premain(String agentArgs, Instrumentation instrumentation) throws InstantiationException {
      InterceptingClassTransformer interceptingClassTransformer = new InterceptingClassTransformer();
      interceptingClassTransformer.init();
      instrumentation.addTransformer(interceptingClassTransformer);
  }
}


premain方法接受兩個參數:

  • agentArgs―字符串參數,用戶選擇作為參數傳遞給Java Agent調用的任何參數。
  • instrumentation來自java.lang instrument包,我們可以添加一個新的ClassFileTransformer對象,它包含Agent的實際邏輯。

第二個選項稱為動態代理。

我們可以做的不是檢測啟動應用程序的方式,而是編寫一小段代碼,接收并連接到現有JVM,并告訴它加載某個代理。

VirtualMachine vm = VirtualMachine.attach(vmPid);
vm.load(agentFilePath);
vm.detach();


此參數agentFilePath與靜態代理方法中的參數完全相同。它必須是agent jar的文件名,因此沒有輸入流也沒有字節。這種方法有兩個警告。第一個是,這是生活在com.sun空間下的私有API,它通常適用于熱點實現。第二個問題是,使用Java9進行排序時,您不能再使用此代碼連接到它正在運行的JVM。

2.1 類轉換

這是我們需要為agent實現的接口,以便轉換類。

public interface ClassFileTransformer {
  byte[] transform(ClassLoader loader, 
                   String className, 
                   Class<?> classBeingRedefined,
                   ProtectionDomain protectionDomain, 
                   byte[] classfileBuffer) 
          throws IllegalClassFormatException;
}

這有點多,但我將解釋方法簽名中的必要參數。第一個重要的是類名。此參數的主要目的是幫助查找并區分要攔截的正確類和其他類。顯然,您可能不想截取應用程序中的每個類,最簡單的方法是使用條件語句進行檢查。

然后是類加載器,它主要用于基本應用程序沒有平坦類空間的環境中,您可能不需要查看它,但一旦遇到更復雜或模塊化的平臺,您就需要查看類加載器。classfileBuffer是檢測前類的當前定義。要截取它,您需要使用庫讀取這個字節數組并截取代碼,然后必須再次轉換回字節碼才能返回。

有幾個字節碼生成庫。您需要進行研究,并根據它是高級API還是低級API、社區大小和許可證自行決定。我放在下面的演示是Javassist,因為我認為它在高級和低級API之間有一個很好的平衡,并且是一個三重許可證,所以幾乎任何人都可以使用它。這

就是ClassFileTransformer實現的主體。

@Override
public byte[] transform(ClassLoader loader, ..)
      throws .. {
  byte[] byteCode = classfileBuffer;
  // If you wanted to intercept all the classs then you can remove this conditional check.
  if (className.equals("Example")) {
      try {
          ClassPool classPool = scopedClassPoolFactory.create(loader, rootPool,
                  ScopedClassPoolRepositoryImpl.getInstance());
          CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
          CtMethod[] methods = ctClass.getDeclaredMethods();
          for (CtMethod method : methods) {
              if (method.equals("main")) {
                  method.insertAfter("System.out.println(\"Logging using Agent\");");
              }
          }
byteCode = ctClass.toBytecode();
          ctClass.detach();
      } catch (Throwable ex) {
          log.log(Level.SEVERE, "Error in transforming the class: " + className, ex);
      }
  }
  return byteCode;
}
ctClass.detach();
      } catch (Throwable ex) {
          log.log(Level.SEVERE, "Error in transforming the class: " + className, ex);
      }
  }
  return byteCode;
}

在這里,從類池中,我們可以直接繞過classfileBuffer獲取類,因為我想使用main方法。我們循環遍歷類定義中的所有方法,得到我們想要的類。我們根本不需要使用字節碼。我們可以簡單地向它傳遞一些合法的Java代碼,然后Javassist將編譯它,生成新的字節碼,并給出定義。

有三種方法可以向方法中插入一些Java代碼。insertAfter(..)在正文末尾插入字節碼。它在正文的末尾插入字節碼。insertAt(..)在正文的指定行插入字節碼,insertBefore(..)在正文的開頭插入字節碼。

2.2 使用Java代理進行實際操作

從指定的鏈接下載示例應用程序和Java Agent。

使用進入路徑并執行命令mvn clean install來構建這兩個repo

現在,您將獲得目標中的jar文件。復制示例應用程序中.jar文件的路徑,并復制Java Agent中-dependencies.jar文件的路徑。

首先,使用命令$java-jar<path of the packaged jar>僅與示例應用程序一起運行應用程序,并觀察輸出。Hi I am main。將在控制臺中打印。

然后,使用命令$ java -javaagent:<path of agent jar file> -jar <path of the packaged jar
file you want to intercept>
并觀察輸出。將在控制臺中另外打印使用代理的日志記錄。這確保java agent被攔截并添加到main方法的主體中。

總之,如果要實現Java Agent,請執行以下操作:

1. 您需要創建兩個Java類。一個是premain方法(JavaAgent),另一個是擴展ClassFileTransformer的類(CustomTransformer

2. 在premain方法的主體內,需要添加擴展ClassFileTransformer的類的對象

3. 然后,您需要在CustomTransformer中的重寫方法transform中添加邏輯。

4. 在轉換方法內轉換字節碼時,可能需要根據用途使用字節碼生成庫。

5. 您需要在清單中指定premain類并構建jar。

6. 使用javaagent標記將代理加載到要攔截的應用程序中。

本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://javakk.com/2318.html?utm_source=tuicool&utm_medium=referral

延伸 · 閱讀

精彩推薦
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 美女在线视频一区二区 | 成人午夜免费网站 | 黄wwww| 国产人妖一区二区 | 白天操夜夜操 | 国产成人精品一区二区三区电影 | 免费淫视频 | 牛牛热这里只有精品 | 亚洲国产精久久久久久久 | 一区二区三区欧美在线 | 国产羞羞视频在线观看 | 久久综合福利 | 国产亚洲在 | 成人一区三区 | 蜜桃视频最新网址 | 欧美性色生活片免费播放 | 久久精品欧美电影 | 不卡国产一区二区三区四区 | 嗯~啊~用力~高h | 91九色论坛 | 精品国产一区在线观看 | 狠狠ri| 成品片a免费直接观看 | www.54271.com| 最新福利在线 | 久久人人爽人人爽人人片av高请 | 国产在线精品区 | 国产视频精品在线 | 欧洲伊人网 | 欧美不卡三区 | 青青草免费观看完整版高清 | 看91视频 | 91资源在线观看 | 91免费高清视频 | 欧美囗交 | chinese军人gay呻吟 | 久久亚洲春色中文字幕久久 | 国产精品久久久久久久久久久天堂 | 久久久av亚洲男天堂 | 国产成人高清在线 | japanese massage tube |