表示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