Java Instrumentation 原理

【字节码】Java Instrumentation 简介 以及 ASM 组合案例 JDK从1.5版本开始引人了java.lang.instrument 包,开发者可以更方便的实现字节码增强。其核心功能由提供,这个接口的方法提供了注册类文件转换器、获取所有已加载的类等功能,允许我们在对已加载和未加载的类进行修改,实现AOP、性能监控等功能。Instrumentation接口的常用方法如下所示。它的addTransformer方法给Instrumentation注册一个类型为ClassFileTransformer的类文件转换器。 阅读详情

文章首发地址
日常工作中用到的很多工具其实都是基于Instrumentation来实现的,比如下面这些:

  • APM产品:Pinpoint、SkyWalking、newrelic等
  • 热部署工具:Intellij idea的HotSwap、Jrebel等
  • Java诊断工具:Arthas等

Instrumentation 简介

JDK从1.5版本开始引入了java.lang.instrument包,开发者可以更方便的实现字节码增强。其核心功能由java.lang.instrument.Instrumentation提供,这个接口的方法提供了注册类文件转换器、获取所有已加载的类等功能,允许我们在对已加载和未加载的类进行修改,实现AOP、性能监控等功能。

Instrumentation接口的常用方法如下所示。

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

Class[] getAllLoadedClasses()

boolean isRetransformClassesSupported();

它的addTransformer方法给Instrumentation注册一个类型为ClassFileTransformer的类文件转换器。ClassFileTransformer接口只有一个transform方法,接口定义如下所示。

public interface ClassFileTransformer {
    byte[] transform(
    ClassLoader loader,
    String className,
    Class<?> classBeingRedefined,
    ProtectionDomain protectionDomain,
    byte[] classfileBuffer
    ) throws IllegalClassFormatException;
}

其中className参数表示当前加载类的类名,classfileBuffer参数是待加载类文件的字节数组。调用addTransformer注册transformer以后,后续所有JVM加载类都会被它的transform方法拦截,这个方法接收原类文件的字节数组,在这个方法中可以做任意的类文件改写,最后返回转换过的字节数组,由JVM加载这个修改过的类文件。如果transform方法返回null,表示不对此类做处理,如果返回值不为null,JVM会用返回的字节数组替换原来类的字节数组。

Instrumentation接口的retransformClasses方法对JVM已经加载的类重新触发类加载。getAllLoadedClasses方法用于获取当前JVM加载的所有类对象。isRetransform-ClassesSupported方法返回一个boolean值表示当前JVM配置是否支持类重新转换的特性。

Instrumentation有两种使用方式:

  • 第一种方式是在JVM启动的时候添加一个Agent的jar包
  • 第二种方式是在JVM运行以后在任意时刻通过Attach API远程加载Agent的jar包

Instrumentation 与 -javaagent 启动参数

Instrumentation的第一种使用方式是通过JVM的启动参数-javaagent来启动,一个典型的使用方式如下所示。

java -javaagent:myagent.jar MyMain

为了能让JVM识别到Agent的入口类,需要在jar包的MANIFEST.MF文件中指定Premain-Class等信息,一个典型的生成好的MANIFEST.MF内容如下所示。

Premain-Class: me.geek01.javaagent.AgentMain
Agent-Class: me.geek01.javaagent.AgentMain
Can-Redefine-Classes: true
Can-Retransform-Classes: true

其中AgentMain类有一个静态的premain方法,JVM在类加载时会先执行AgentMain类的premain方法,再执行Java程序本身的main方法,这就是premain名字的来源。在premain方法中可以对class文件进行修改。这种机制可以认为是虚拟机级别的AOP,无须对原有应用做任何修改就可以实现类的动态修改和增强。

premain方法签名如下所示。

public static void premain(String agentArgument, Instrumentation instrumentation) throws Exception

第一个参数agentArgument是agent的启动参数,可以在JVM启动时指定。以下面的启动方式为例,它的agentArgument的值为"appId:agent-demo,agentType:singleJar"。

java -javaagent:<jarfile>=appId:agent-demo,agentType:singleJar test.jar

第二个参数instrumentation是java.lang.instrument.Instrumentation的实例,可以通过addTransformer方法设置一个ClassFileTransformer。

静态Instrumentation的处理过程如下,JVM启动后会执行Agent jar中的premain方法,在premain中可以调用Instrumentation对象的addTransformer方法注册ClassFile-Transformer。当JVM加载类时会将类文件的字节数组传递给transformer的transform方法,在transform方法中可以对类文件进行解析和修改,随后JVM就可以加载转换后的类文件。整个过程如图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V0ASffUd-1689239424181)(…/…/…/asserts/img/java-instrumentation1.png)]

JVM Attach API 介绍

在JDK5中,开发者只能在JVM启动时指定一个javaagent,在premain中操作字节码,这种Instrumentation方式仅限于main方法执行前,存在很大的局限性。从JDK6开始引入了动态Attach Agent的方案,可以在JVM启动后任意时刻通过Attach API远程加载Agent的jar包,比如大名鼎鼎的arthas工具就是基于Attach API实现的。

加载Agent的jar包只是Attach API的功能之一,我们常用jstack、jps、jmap工具都是利用Attach API来实现的。

JVM Attach API 底层原理

JVM Attach API的实现主要基于信号和UNIX域套接字

信号

信号是某事件发生时对进程的通知机制,也被称为“软件中断”。信号可以看作一种非常轻量级的进程间通信,信号由一个进程发送给另外一个进程,只不过是经由内核作为一个中间人转发,信号最初的目的是用来指定杀死进程的不同方式。

每个信号都有一个名字,以“SIG”开头,最熟知的信号应该是SIGINT,我们在终端执行某个应用程序的过程中按下Ctrl+C一般会终止正在执行的进程,这是因为按下Ctrl+C会发送SIGINT信号给目标程序。每个信号都有一个唯一的数字标识,从1开始,常见的信号量列表如表所示。

信号名编号描述
SIGINT2键盘中断信号(Ctrl+C)
SIGQUIT3键盘退出信号
SIGKILL9“必杀信号”(sure kill),应用程序无法忽略或捕获,总会被杀死
SIGTERM15终止信号

在Linux中,一个前台进程可以使用Ctrl+C进行终止,对于后台进程需要使用kill加进程号的方式来终止,kill命令是通过发送信号给目标进程来实现终止进程的功能。默认情况下,kill命令发送的是编号为15的SIGTERM信号,这个信号可以被进程捕获,选择忽略或正常退出。目标进程如果没有自定义处理这个信号就会被终止。对于那些忽略SIGTERM信号的进程,可以指定编号为9的SIGKILL信号强行杀死进程,SIGKILL信号不能被忽略也不能被捕获和自定义处理。

UNIX域套接字(UNIX Domain Socket)

使用TCP和UDP进行socket通信是一种广为人知的socket使用方式,除了这种方式以外还有一种称为UNIX域套接字的方式,可以实现同一主机上的进程间通信。虽然使用127.0.01环回地址也可以通过网络实现同一主机的进程间通信,但UNIX域套接字更可靠、效率更高。Docker守护进程(Docker daemon)使用了UNIX域套接字,容器中的进程可以通过它与Docker守护进程进行通信。MySQL同样提供了域套接字进行访问的方式。

在UNIX世界,一切皆文件,UNIX域套接字也是一个文件,下面是在某文件夹下执行ls-l命令的输出结果。

ls -l
srwxrwxr-x. 1 ya ya        0 9月   8 00:26 tmp.sock
drwxr-xr-x. 5 ya ya    4096 11月  29 09:18 tmp
-rw-r--r--. 1 ya ya   14919 10月  31 2017  test1.png

ls-l命令输出的第一个字符表示文件的类型,“s”表示这是一个UNIX域套接字,“d”表示这个是一个文件夹,“-”表示这是一个普通文件。

两个进程通过读写这个文件就实现了进程间的信息传递。文件的拥有者和权限决定了谁可以读写这个套接字。

UNIX域套接字与普通套接字的对比和区别是什么?

  • UNIX域套接字更加高效,它不用进行协议处理,不需要计算序列号,也不需要发送确认报文,只需要读写数据即可。
  • UNIX域套接字是可靠的,不会丢失数据,普通套接字是为不可靠通信设计的。
  • UNIX域套接字的代码可以非常简单地修改为普通套接字。
JVM Attach API的执行过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpnspyjh-1689239424182)(…/…/…/asserts/img/java-instrumentation2.png)]

javaagent 实现原理:Instrument 机制、Attach功能 类加载过程中, defineClass()方法会将二进制文件读取得到class对象, redefineClasses就是可控的再次进行这一过程.对于已经加载的类, 该方法通过使用提供的新的字节码文件进行替换,现有的类文件字节不会被使用,就像从源头进行重新编译以进行修复和继续调试时一样。redefineClasses的工作流程重定义类的请求会被JVM包装成一个VM_RedefineClasses类型的VM_Operation,VM_Operation是JVM内部的一些操作的基类,包括GC操作等。 阅读详情

相关推荐

Windows10开机无限蓝屏(SrtTrail.txt)

这个问题已经有很多的大佬发过解决办法了,这里仅仅作为自己日后方便查找所写文章 无法开机——自动修复失败,报SrtTrail.txt文件错误,且陷入无限蓝屏的循环 事故 故事的起因是这样的: 开开心心的组装电脑,花了几天时间来配置,然后发现USB3.0的接口太少,于是在某宝上搞到一张pcie转7口USB3.0的转接卡,往电脑上一插 插电,开机,电流轻松跑上去 然后,它和原来的磁盘阵列卡冲突,跳过阵列卡自检直接进入系统,boom,就导致了这场悲剧 解决方法 在蓝屏的界面找到:疑难解答->通过命令提示符 使

Holo__的博客 3万+

JAVA Instrumentation

什么是Instrumentation? java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。 Java SE5中使用JVM TI替代了JVM PI和JVM DI。提供一套代理机制,支持独立于JVM应用程序之外的程序以代理的方式连接和访问JVM。java.lang.instrument是在JVM TI的基础上提供的Java版本的实现。 Instrumentatio

通往神秘的道路的专栏 4084

STM32F103到F407移植OLED,为啥F4屏幕不亮?一个延时函数搞定时序问题

本文详细分析了STM32F103到F407移植OLED时屏幕不亮的问题,指出时钟频率差异导致的时序问题是关键原因。通过对比F103和F407的时钟架构差异,提供了精确延时函数的实现方法,并指导在I2C通信关键点插入适当延时,确保OLED正常显示。文章还涵盖了完整的测试方案和高级优化技巧,帮助开发者彻底解决移植中的时序问题。

weixin_30642561的博客 549

一篇文章带你揭开 Java Instrumentation 的原理

文章目录一、前言二、热部署初识三、Java Instrumentation四、Java Instrumentation 静态代码示例五、Java Agent 示例 —— attach的使用 一、前言 日常开发中避免不了,修改了代码重新启动应用去验证问题,如果没有热部署,则需要每次修改完就去编译代码再启动,这样子的操作看似简单, 但很耗时,特别电脑配置不高,或者项目比较大的情况 二、热部署初识 热部署其实就是在代码运行时去加载我们动态现在修改过的代码到服务器上,诸如 SpringBoot的devtools插

啊狸的Java的博客 2162

地下水热耦合模拟FEFLOW建模

2.3 依据讲解内容,练习构建地下水数值模型(例二),学会各种源汇项、边界条件、时间序列、节点参数的添加及模拟结果的导出。对于真实模型,学习如何建立概念模型、数学模型,练习模型的各种参数和源汇项输入,进行溶质运移、水热模拟。3.通过多种实践案例应用,掌握实践工作中常见项目的模型搭建及特殊问题处理方法。4.1学习水热模型抽灌模式,网格剖分、边界条件、初始温度场赋值。3.3练习模型的各种参数和源汇项输入,进行水流和溶质运移模拟。2.掌握水热耦合的模拟方法及典型项目应用问题处理。2.4根据模拟结果,

weixin_55561616的博客 964

一分钟理解 “熔断“, “限流“ 与 “降级“

熔断,本质是一种“故障隔离”机制,用于当某个依赖服务出现持续故障(如响应超时、错误率飙升)时,暂时切断对该服务的调用,避免故障扩散到整个系统,防止“雪崩效应”;待依赖服务恢复正常后,再逐步恢复调用。其核心逻辑参考了现实中的“电路保险丝”——电路过载时,保险丝熔断,切断电路,保护电器不被烧毁;故障排除后,更换保险丝,电路恢复正常。闭合状态(Closed):正常状态,请求可以正常调用依赖服务,同时监控调用的错误率、超时率等指标。打开状态(Open)

h a 6 6 6 c k 为 你解决复杂难题! 1477

字节码进阶之java Instrumentation原理详解

Java Instrumentation是Java API的一部分,它允许开发人员在运行时修改类的字节码。使用此功能,可以实现许多高级操作,例如性能监控、代码覆盖率分析等。通过Java提供的Instrumentation接口,我们能够在运行时改变和监控Java程序,这种能力在许多场景中都非常有用,比如性能调优、故障排查、代码覆盖率分析等。然而,Instrumentation接口的使用和字节码操作本身都是高级主题,需要深入理解JVM和字节码的工作原理。

日拱一卒无有尽,功不唐捐终入海 2281

Java零基础之多线程篇:线程间如何通信?

随着计算机技术的发展,多线程编程已经成为现代软件开发中的一个重要方向。在多线程编程中,线程间的通信是一个非常关键的问题。在Java开发语言中,Java提供了一些机制来实现线程间的通信,帮助开发者协调不同线程之间的执行顺序和数据交换。本文将介绍Java多线程编程中的线程间通信的相关知识。首先,我们将从简介开始,介绍线程间通信的基本概念和原理。然后,我们将通过源代码解析的方式,深入探讨Java中实现线程间通信的方法。接着,我们将给出一些应用场景案例,展示线程间通信在实际开发中的应用。

喵手的博客 1558

快速入门-Java Instrumentation

特性/库ASMByteBuddyCGLIBJavassist功能字节码修改、类重新定义字节码操作与生成字节码增强与生成继承代理字节码操作与生成使用场景AOP、性能监控、动态更新字节码增强、性能优化动态代理、AOP、字节码增强动态代理(无接口)字节码修改、动态生成易用性复杂,低级别控制低级,复杂简洁,流式API简单,继承代理简单,API 简洁性能较高,依赖 JVM 的优化高效,但底层控制复杂高效且灵活较高,继承代理性能较好,适合动态生成优点。

sc35262的博客 1032

指纹浏览器降维打击(下):Cloudflare Turnstile 与 hCaptcha 的底层交互逻辑

本文将深度拆解:Turnstile 与 hCaptcha 的 Iframe 沙箱通信机制,动态混淆 JS 与 PoW(工作量证明)的物理破解法则,以及如何通过 C++ 底层事件合成与环境基因强绑定,实现验证码的“无感过验”。

数据知道的博客 422

LeRobot 入门教程(七)数据集

LeRobot Dataset v3.0 是机器人学习数据的标准化格式,支持多模态时间序列数据和视频的统一访问。该版本通过基于文件的存储(Parquet/MP4)、关联元数据和Hub原生流式处理等新特性,显著提升了性能并降低了存储开销。文档详细介绍了格式设计、安装使用、数据记录与加载方法,以及从v2.1迁移到v3.0的步骤,特别针对大型数据集(如DROID 1.0.1)的处理提供了SLURM集群移植方案。v3.0通过优化文件组织和元数据管理,实现了更快的加载速度、更高的内存效率和更好的可扩展性。

2506_90492529的博客 2055

Java的Instrumentation类原理分析

利用 java.lang.instrument 做动态 Instrumentation 是 Java SE 5 的新特性,它把 Java 的 instrument 功能从本地代码中解放出来,使之可以用 Java 代码的方式解决问题。使用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。

JavaEdge全是干货的技术号 4130

电子电器架构刷写方案——General Flash Bootloader

### 文章大体有如下内容: ### 1、简介 ### 2、刷写系统概述 ### 3、Flash Bootloader刷写流程 ### 4、Flash Bootloader架构介绍 ### 5、关于刷写的思考

Soly_kun的博客 2211

Java Agent技术深度解析:从Instrumentation原理到Atlassian产品实践

Java Agent是Java平台提供的一种底层技术机制,它基于Java Instrumentation API,允许开发者在JVM启动时或运行时动态修改类的字节码。其核心原理是通过ClassFileTransformer接口拦截类加载过程,利用ASM或Javassist等字节码操作库对目标类进行精准修改。这项技术的核心价值在于提供了对运行中Java应用程序进行无侵入式监控、诊断和增强的能力,广泛应用于应用性能监控(APM)、热部署和线上诊断等场景。在具体实践中,Java Agent技术可以用于深度理解企业

weixin_26913055的博客 326

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

JVM字节码-Instrumentation原理

Instrumentation原理

StivenYang 284

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

今天一起来探究一下Instrumentation这个接口有多丰富的操作

通过Instrumentation接口,开发者可以实现对Java应用程序的监控、诊断和性能优化,为Java程序的稳定和高效运行提供了强有力的支持。在JVM内部,Instrumentation接口作为一个重要的扩展接口,为开发者提供了丰富的操作方法,可以实现对Java类的监控和操作。Instrumentation作为JVM提供的重要接口,将继续发挥重要作用,为开发者提供更多的操作方法和监控手段,帮助他们更好地理解和优化Java应用程序的运行状态。Instrumentation在Java程序监控中的应用。

KongDere的博客 505

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

浅谈jvm中Instrumentation的实现

想必不少人听说过javaagent,但是很少人听说Instrumentation,其实Instrumentation就是javaagent的实现机制,说到Instrumentation,就必须想了解java的attach机制,那就先说下attach的实现。        大家进行jstack的时候,是不是经常看到两个线程Signal Dispatcher和 Attach Listener线程,可...

移动开发http://www.software8.co/wzjs/yidongkaifa/ 286

Instrumentation 应用简介

引用: java-instrumentation 引用:Instrumentation 新功能 简介 java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。 场景 一个ATM应用程序,允许我们取钱 还有一个Java代理,它允许我们通过衡量投入的时间...

dark 1194

Java Agent(一)——初步认识 `Instrumentation`

Java Agent 是通过 Instrumentation API 进行操作的 Java 程序,它可以在 JVM 启动时或类加载时附加到应用程序的运行时环境中。Java Agent 允许我们动态地操作类的字节码,从而能够在不修改源代码的情况下进行增强或修改应用行为。

小蜗牛的珍贵百宝箱 983

JAVA的Instrumentation类使用介绍

介绍: Instrumentation 是java1.6才有的,跟aop有点像,只不过这是java提供给针对JVM对外接口的开发类,所以非常灵活,也更细粒度,说白了就是性能好; Instrumentation提供了两种使用方式 第一种是通过JVM启动参数的形式: -javaagent(也就是单独建立一个项目编写好代码之后打成jar包供另一个使用程序通过代理形式引入.),启动时处理 一般我们会命名premain函数处理 第二种与第一种有些相似,但它是运行是处理;不需要通过启动参数,通过attach工具

无忧草 1883

JVM中Instrumentation实现

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33691817的博客 292

Java - Instrumentation

使用JRebel启动工程时加上VM参数时有一个参数是"-javaagent:D:\jrebel_5.6.0\jrebel.jar"。 javaagent是什么? java -help后看到如下信息: Java代理不是应用程序中的一部分,instrument支持Java以代理的形式监控或重新定义运行中的服务。我们可以在不修改程序代码的前提下通过Instrumentation ...

aozhangping6851的博客 118

【精通 JVM 原理】浅析 JavaAgent & Instrumentation 机制

浅析 JavaAgent & Instrumentation 机制 前言 本文主要内容 1、JVM的字节码指令,方法调用机制 2、Java类加载器 3、JavaAgent 4、Java Instrumentation 词汇说明 Java Virtual Machine (JVM) 什么是字节码? 机器码 机器码(machine code)是CPU可直接解读的指令。机器码与硬件等有关,不同的...

AI天才研究院 8863

Java利用Instrumentation获取对象大小升级版

    之前发过一个Java利用Instrumentation获取对象大小的博客,这次修复了一些Bug,应该是非常准确了,除了一种情况,那就是下面代码里面main方法里的情况: /** * 因为要用到java.lang.instrument.Instrumentation, * 本代码需要打成jar包以javaagent运行,manifest.mf文件内容如下 Manifes...

teasp的专栏 688

JAVA Agent 简析及开发示例

Java.lang.Instrument包是在JDK5引入的,程序员通过修改方法的字节码实现动态修改类代码。这通常是在类的main方法调用之前进行预处理的操作,通过java指定该类的代理类来实现。 代理 (agent) 是在你的main方法前的一个拦截器 (interceptor),也就是在main方法执行之前,执行agent的代码。agent的代码与你的main方法在同一个JVM中运行,并被同一个

Kuzury 1万+
上一篇: SpringBoot可以同时处理多少请求?
下一篇: 除了单测、写main方法,还有其他验证方式吗?试试Java JShell吧!
Walter Sun
博客等级 码龄9年 1726粉丝 288原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值