表示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
的類必須實現一個名為
1
|
public static void premain(String agentArgs, Instrumentation inst) |
此方法構成代理的入口點,就像常規Java程序的入口點是主方法一樣。
JVM初始化后,調用 premain
方法;這表示代理??梢杂袔讉€這樣的代理;因此,將根據JVM初始化期間指定的代理的順序調用每個 premain
方法。如果找不到特定的 premain
方法,JVM會依次調用 premain
方法的重載版本,例如
1
|
public static void premain(String agentArgs) |
代理類還可能包含JVM在agent啟動后通常使用的方法,例如
1
2
|
public static void agentmain(String agentArgs, instrumentation inst) |
或者,它的重載版本
1
|
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。
這是我們將在示例中使用的示例類。這沒什么特別的。
1
2
3
4
5
6
7
8
9
|
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
方法來獲取運行時主對象的內存使用情況。
1
2
3
4
5
6
7
8
9
|
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
目錄中。
我們的示例所需的內容非常基本:
1
2
|
Manifest-Version: 1.0 Premain-Class: com.mano.examples.MyAgentClass |
現在,編譯所有Java文件以創建類文件。最后,創建JAR文件,如下所示:
1
2
|
jar -cmf META-INF/MANIFEST.MF myagent.jar com/mano/examples/ MyAgentClass. class |
五、部署Java Agents
創建代理后,它將作為JAR文件部署。清單文件中的屬性指定將加載以啟動代理的代理類。請注意,啟動代理有很多方法:使用命令行、運行時或作為JAR可執行文件。我們將在這里使用命令行。
使用命令行運行Agents
代理
命令行是:
1
|
java -javaagent:myagent.jar -cp . com.mano.examples.Main |
這表示 premain
方法將在應用程序執行之前運行,并創建 Main 實例的大小。
結論:
儀器API所提供的功能可以進行多種創新。AOP是一個簡單的例子。雖然Java
代理和Java Instrumentation API
在應用程序開發中不經常使用,但是關于它的全部內容的想法可以澄清Java
的許多其他方面。這里給出的代碼示例是初步的,只是為了說明如何創建代理。
到此這篇關于Java Agents
代理是什么的文章就介紹到這了,更多相關Java Agents
代理內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.tuicool.com/articles/jQ3QzaI