java agent介绍

java agent本质上可以理解为一个插件,该插件就是一个精心提供的jar包,这个jar包通过JVMTI(JVM ToolInterface)完成加载,最终借助JPLISAgent(JavaProgramming Language Instrumentation Services Agent)完成对目标代码的修改。

java agent技术的主要功能如下:

  • 可以在加载java文件之前做拦截把字节码做修改

  • 可以在运行期将已经加载的类的字节码做变更

  • 还有其他的一些小众的功能

  • 获取所有已经被加载过的类

  • 获取所有已经被初始化过了的类

  • 获取某个对象的大小

  • 将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载

  • 将某个jar加入到classpath里供AppClassloard去加载

  • 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配

java Instrumentation API

实现agent启动方法

Java Agent支持目标JVM启动时加载,也支持在目标JVM运行时加载,这两种不同的加载模式会使用不同的入口函数,如果需要在目标JVM启动的同时加载Agent,那么可以选择实现下面的方法:

public static void premain(String agentArgs, Instrumentation inst);

public static void premain(String agentArgs);

如果希望在目标JVM运行时加载Agent,则需要实现下面的方法:

public static void agentmain(String agentArgs, Instrumentation inst);

public static void agentmain(String agentArgs);

这两组方法的第一个参数AgentArgs是随同“–javaagent”一起传入的程序参数,如果这个字符串代表了多个参数,就需要自己解析这些参数。inst是Instrumentation类型的对象,是JVM自动传入的,我们可以拿这个参数进行类增强等操作。

MANIFEST.MF 作用

If you remove META-INF from a jar then there is no MANIFEST.MFand so java -jar can't find the main class.

Agent需要打包成一个jar包,在ManiFest属性中指定“Premain-Class”或者“Agent-Class”,且需根据需求定义Can-Redefine-Classes和Can-Retransform-Classes:

Manifest-Version: 1.0

Implementation-Title: apm-agent

Implementation-Version: 6.6.0

Built-By: wusheng

Specification-Vendor: The Apache Software Foundation

Can-Redefine-Classes: true

Specification-Title: apm-agent

Implementation-Vendor-Id: org.apache.skywalking

Implementation-Vendor: The Apache Software Foundation

Premain-Class: org.apache.skywalking.apm.agent.SkyWalkingAgent

Can-Retransform-Classes: true

Created-By: Apache Maven 3.6.1

Build-Jdk: 1.8.0_232

Specification-Version: 6.6

Implementation-URL: http://maven.apache.org

启动时修改

启动时修改主要是在jvm启动时,执行native函数的Agent_OnLoad方法,在方法执行时,执行如下步骤:

  • 创建InstrumentationImpl对象

  • 监听ClassFileLoadHook事件

  • 调用InstrumentationImpl的loadClassAndCallPremain方法,在这个方法里会去调用javaagent里MANIFEST.MF里指定的Premain-Class类的premain方法

运行时修改

运行时修改主要是通过jvm的attach机制来请求目标jvm加载对应的agent,执行native函数的Agent_OnAttach方法,在方法执行时,执行如下步骤:

  • 创建InstrumentationImpl对象

  • 监听ClassFileLoadHook事件

  • 调用InstrumentationImpl的loadClassAndCallAgentmain方法,在这个方法里会去调用javaagent里MANIFEST.MF里指定的Agentmain-Class类的agentmain方法

agent通过 org.apache.skywalking.apm.agent.core.boot.BootService 实现了整体的插件化,agent启动会加载所有的BootService实现,并通过 ServiceManager 来管理这些插件的生命周期,采集jvm指标、gRPC连接管理、调用链数据维护、数据上报OAP这些服务均是通过这种方式扩展。

然后,agent还通过bytebuddy以javaagent的模式,通过字节码增强的机制来构造AOP环境,再提供PluginDefine的规范方便探针的开发,最终实现非侵入性的数据埋点,采集调用链数据。

参考链接:

Instrumentation 新功能

https://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html

JVM 源码分析之javaagent 原理完全解读

https://www.infoq.cn/article/javaagent-illustrated/

破解 Java Agent 探针黑科技!

https://xie.infoq.cn/article/a6012a49401802c963d416970

通过使用 Byte Buddy,便捷地创建 Java Agent

https://www.infoq.cn/article/Easily-Create-Java-Agents-with-ByteBuddy

最全面!一文让你看懂无侵入的微服务探针原理

https://www.infoq.cn/article/q1ivDiHCAFwKYF8Zmyj5

从 0-1 开发 Java 性能剖析工具

https://www.infoq.cn/article/esVkcjQPTh3YzDFUCUKd

虚拟机技术

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

vivo 调用链Agent 原理及实践

https://xie.infoq.cn/article/c98b32ef8bf0193e4bc40be70

ASM

https://asm.ow2.io/faq.html

Byte Buddy 教程

https://notes.diguage.com/byte-buddy-tutorial/

JVMTI(JVMTool Interface)

https://docs.oracle.com/en/java/javase/16/docs/specs/jvmti.html

流概念

https://ci.apache.org/projects/flink/flink-docs-release-1.11/concepts/index.html

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐