第五章 Java agent

407 阅读3分钟

前言

skywalking 使用java agent技术进行字节码操作监听我们感兴趣的类或者方法,进行类似于“AOP” 切面监控。所以有必要对java agent 进行一个大概的讲解

Java agent

java-agent 有两种,分别是:JDK5引入的 premain,和 JDK6 引入的 agentmain,前者可以在 JVM 加载类之前拦截并修改字节码,后者可以在运行时将 agent 附加到到任意的虚拟机中来修改字节码,并且,修改后可以立马更新,不需要重新加载类,因此可以实现热修改,并且比自定义类加载器更方便

java agent 使用

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-Redefine-Classes 和 Can-Retransform-Classes 选项 。插件生成(maven 插件 maven-shade-plugin)
  2. 创建一个 Agent-Class 指定的类,该类必须包含 agentmain 方法
  3. 将MANIFEST.MF 和 Agent 类打成 jar 包
  4. 将 jar 包载入目标虚拟机。目标虚拟机将会自动执行 agentmain 方法执行方法逻辑,同时,ClassFileTransformer 也会长期有效,在每一个类加载器加载 Class 的时候都会拦截

MANIFEST.MF 三个运行的参数:

  • Agent-Class 或者 Premain-Class 指定程序的入口,类似于main 方法一样。得指定类

  • Can-Redefine-Classes 是否能重定义原始类

  • Can-Retransform-Classes 已存在的重新定义类是否能被再次覆盖

premain

在 JDK 1.5 中,Java 引入了 java.lang.Instrument 包,该包提供了一些工具帮助开发人员在 Java 程序运行时,动态修改系统中的 Class 类型。其中,使用该软件包的一个关键组件就是 Java agent。从名字上看,似乎是个 Java 代理之类的,而实际上,他的功能更像是一个Class 类型的转换器,他可以在运行时接受重新外部请求,对Class 类型进行修改。

其实介绍描述那么多可以简单理解为,静态的代码注入。代码只能在加载前修改,加载完成后。就不能动态的修改调整。

特性:

  • java -javaagent 参数启用
  • 入口方法premain
  • 代码零侵入
  • 操作自由度更高。任意修改字节码(jvm能验证通过)
  • 应用框架 APM 类型框架 skywalking、pinpoint等
agentmain

premain 只能在类加载之前修改字节码,类加载之后无能为力,只能通过重新创建ClassLoader 这种方式重新加载。而 agentmain 就是为了弥补这种缺点而诞生的。

特性:

  • 使用attach api 方式挂载。和premain 不同
  • 入口方法 agentmain()方法
  • 自由度很低,基本上只能做到监控。不能做任何修改调整
  • 应用的 阿里的 Arthas

demo演示 有兴趣的同学可以看一下这个演示demo gitee.com/xlr_ru/java…

注意事项:

1. 动态多次加载会有内存溢出风险!!!字节码加载到jvm内存元空间。并不会清理,考虑加载一次缓存起来使用

2. agentmain  和 premain 的入口标签是不一样的。可以和博主一样,这样冗余去写。让系统自动辨识

参考文档地址