什麼是Java Agents代理?

老K的Java博客 2021-09-18 20:37:27 阅读数:541

java agents 代理

Java代理Agents通過提供使我們能够侵入JVM中正在運行的Java程序的服務,在最底層工作。Java的這一强大但不可思議的部分具有在錯誤操作時使JVM崩潰的能力。本文簡要介紹了這個概念,並介紹了它的工作原理。

錶示Java Agents的類顯然只不過是Java API庫中的任何其他類。但是,讓它們與眾不同的是,它們遵循某種約定,這種約定使Java代碼能够攔截JVM中運行的另一個應用程序。其目的只是讓代理調查或修改字節碼。這是一個强大但不可思議的特性,超出了Java程序通常的功能範圍。在某種程度上,它可以闖入一個程序,修改字節碼或造成混亂。請理解,這不是添加到Java中的新技術或功能。自JDK1.5以來,它一直是庫的一部分。這意味著使用它們也有一些真正的好處。但是,在討論它們的優點以及如何使用它們之前,讓我們先看看在Java中哪裏可以找到它們。

Java Agents 和 Instrumentation

Java agent是Java Instrumentation API的一部分。檢測API提供了一種修改方法字節碼的機制。這可以靜態和動態地完成。這意味著我們可以通過向程序中添加代碼來更改程序,而不必涉及程序的實際源代碼。結果可能會對應用程序的整體行為產生重大影響。

Java agent和instrumentation API比特於名為Java.lang.intrumentation的包中。

Java agent的使用

Java agent可以有多種用途,如面向方面編程(AOP)、變异測試、評測等。AOP通常會在不更改代碼的情况下向現有程序添加日志記錄或安全性等行為。它使用Java代理來操作字節碼,並將其功能與程序結合起來。監視JVM級別的參數,如對象創建、垃圾收集、線程執行等,是探查器的工作。評測工具顯著地使用Java代理評測執行中程序的JVM參數。

還有許多其他情况下,Java agent和instrumentation API非常方便。

如何編寫Java代理

實現Java agent的類必須實現一個名為

public static void premain(String agentArgs, Instrumentation inst)

此方法構成代理的入口點,就像常規Java程序的入口點是主方法一樣。

JVM初始化後,調用premain方法;這錶示代理。可以有幾個這樣的代理;因此,將根據JVM初始化期間指定的代理的順序調用每個premain方法。如果找不到特定的premain方法,JVM會依次調用premain方法的重載版本,例如

public static void premain(String agentArgs)

代理類還可能包含JVM在agent啟動後通常使用的方法,例如

public static void agentmain(String agentArgs, instrumentation inst)

或者,它的重載版本

public static void agentmain(String agentArgs)

這是JVM的典型例程,一旦該例程完成,就會調用main方法。

另一件重要的事情是,Java代理在開發期間必須在資源目錄的META-INF文件夾中包含MANIFEST.MF文件。此文件包含有關包分發的元數據信息。此文件作為其JAR打包的一部分包含。MANIFEST.MF文件中包含的屬性提供了有關為什麼需要這樣做的線索。這些屬性如下所示:

  • Premain-class:此屬性定義代理類。如果未定義此屬性,JVM將中止。
  • Agent-class:它定義了在JVM啟動後啟動Java代理的機制。如果此屬性未定義,代理將不會啟動。
  • Can-Redefine-Classes:這定義了代理重新定義類的能力。該值可以是true或false。
  • Can-Retransform-Classes:這定義了代理重新傳輸類的能力。該值可以是true或false。
  • Can-Set-Native-Method-Prefix:這定義了代理設置本機方法前綴的能力。該值可以是true或false。
  • Boot-Class-Path:定義引導類加載程序的搜索路徑列錶。

一個簡單的例子

探查器工具通常通過從JVM提取信息來報告運行時Java對象的不同參數。這些參數包括關於使用檢測框架的對象的內存使用等信息。

1. 這裏我們使用premain方法創建一個代理類。

2. 傳遞給premain方法的檢測實例將提供有關對象大小的信息。

3. 將代理類與MANIFEST.MF文件一起打包到JAR文件中。

4. 使用命令行參數將代理傳遞給JVM。

這是我們將在示例中使用的示例類。這沒什麼特別的。

package com.mano.examples;public class Main { public static void greet(String msg){ System.out.println(msg); } public static void main(String[] args){ greet("Hello Agents"); }}

代理類

帶有premain方法的instrumentation agent類用於檢索我們需要的信息。插裝接口的實現被傳遞給premain方法。我們使用由instrumentation接口定義的getObjectSize方法來獲取運行時主對象的內存使用情况。

package com.mano.examples;import java.lang.instrument.Instrumentation;public class MyAgentClass { public static void premain(String agentArgs, Instrumentation inst) { System.out.println(inst.getObjectSize (new Main())) }}

之後,我們必須創建MANIFEST.MF文件。這只是一個文本文件,我們在其中放置與代理類相關的信息。JVM將使用它來加載代理。該文件通常存儲在META-INF目錄中。我們的示例所需的內容非常基本:

Manifest-Version: 1.0Premain-Class: com.mano.examples.MyAgentClass

現在,編譯所有Java文件以創建類文件。最後,創建JAR文件,如下所示:

jar -cmf META-INF/MANIFEST.MF myagent.jar com/mano/examples/ MyAgentClass.class

部署Java Agents

創建代理後,它將作為JAR文件部署。清單文件中的屬性指定將加載以啟動代理的代理類。請注意,啟動代理有很多方法:使用命令行、運行時或作為JAR可執行文件。我們將在這裏使用命令行。

使用命令行運行Agents代理

命令行是:

java -javaagent:myagent.jar -cp . com.mano.examples.Main

這錶示premain方法將在應用程序執行之前運行,並創建Main實例的大小。

結論

儀器API所提供的功能可以進行多種創新。AOP是一個簡單的例子。雖然Java代理和Java Instrumentation API在應用程序開發中不經常使用,但是關於它的全部內容的想法可以澄清Java的許多其他方面。這裏給出的代碼示例是初步的,只是為了說明如何創建代理。

原文地址:https://www.developer.com/design/what-is-java-agent/

版权声明:本文为[老K的Java博客]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918203726669q.html