文章目录

  • 前言
  • 一、Instrumentation类
    • 1.addTransformer(ClassFileTransformer transformer, boolean canRetransform)
    • 2.addTransformer(ClassFileTransformer transformer)
    • 3.removeTransformer(ClassFileTransformer transformer)
    • 4.isRetransformClassesSupported()
    • 5.retransformClasses(Class… classes) throws UnmodifiableClassException
    • 6.isRedefineClassesSupported()
    • 7.redefineClasses(ClassDefinition… definitions) throws ClassNotFoundException, UnmodifiableClassException
    • 8.isModifiableClass(Class theClass)
    • 9.getAllLoadedClasses()
    • 10.getInitiatedClasses(ClassLoader loader)
    • 11.getObjectSize(Object objectToSize)
    • 12.appendToBootstrapClassLoaderSearch(JarFile jarfile)
    • 13.appendToSystemClassLoaderSearch(JarFile jarfile)
    • 14.isNativeMethodPrefixSupported()
    • 15.setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
  • 二、ClassFileTransformer类
    • 1.transform
  • 总结

前言

Instrumentation主要是提供Java代码增强功能。例如为了提供收集数据的功能,可以通过字节码增强技术,对类的方法进行增强。由于代码是添加的,所以他不会修改原来的状态。通过这个API,我们可以开发各种工具,例如监控的客户端,profiles,代码覆盖率分析工具以及事件的日志埋点工具。
使用方式:
一是在java启动的时候添加启动参数javaagent将你的增强包加载进来,会在permain里把Instrumentation传过来
二是使用VirtualMachine的API来进行。
具体的做法是调用VirtualMachine.attach(java pid),会在agentmain方法里把Instrumentation实例传过来


提示:以下是本篇文章介绍其中的方法

一、Instrumentation类

1.addTransformer(ClassFileTransformer transformer, boolean canRetransform)

代码如下(示例):

addTransformer(ClassFileTransformer transformer, boolean canRetransform)

函数的作用是注册一段代码增强逻辑,它能对所有已定义的类生效(除了通过依赖的transformer进行定义的类)。
当一个类被加载的时候,或者是redefineClasses方法被调用的时候,或者是retransformClasses方法被调用的时候(前提是canRetransform的参数是true),这个函数里注册的transformer就被调用了。
至于transformer之间调用的顺序,则是由添加的先后顺序来决定的(假设有多个agent对同一个类的方法进行了增强,他们是按照先后顺序来执行的)可以想象一下管道命令,是一样的。
异常问题,值得注意的是,如果这个方法在执行的时候发生了异常,jvm不会中断,他会继续进行下一个transformer的执行。
重复add的问题,同一个transformer可能会被add多次,这个是不被推荐的,add多次最好new新的对象进行。
当传入的transformer是null的时候,这个方法会抛出NullPointException的异常,当canRetransform被设为true,而JVM虚拟机被设置为不可被reTransfrom的时候(参见isRetransformClassesSupported方法),会抛出UnsupportedOperationException异常。

2.addTransformer(ClassFileTransformer transformer)

代码如下(示例):

addTransformer(ClassFileTransformer transformer)

等同于addTranformer(transformer,false);

3.removeTransformer(ClassFileTransformer transformer)

代码如下(示例):

removeTransformer(ClassFileTransformer transformer)

移除已注册的transformer。未来被定义的类将不会被应用这个transformer。由于类加载的多线程语义性,可能被移除的transformer还会依然生效,所以业务方在编写的时候要处理好,做好防御性编程。

4.isRetransformClassesSupported()

代码如下(示例):

isRetransformClassesSupported()

返回当前的JVM配置是否支持类的reTransform。这个取决于你的javaagent里manifest的配置项的Can-Retransform-Classes配置

5.retransformClasses(Class… classes) throws UnmodifiableClassException

代码如下(示例):

retransformClasses(Class… classes) throws UnmodifiableClassException

函数的用途是对传入的classes执行transform,一般用于agentmain的方式。因为agentmain的方式是在class已经被加载完了之后attch到jvm上的,这个时候只有通过这种方式来修改原来的类的行为。

所以在add的时候,canTransform设置为false的将会被忽略,只有设置为true的才会被执行。如果你的jvm的Can-Retransform-Classes被设置为false,会抛出异常。同时如果你的类有问题,可能会抛出ClassFormatError,NoClassDefFoundError,ClassCircularityError,LinkageError异常,如果传入的是null,会报NullPointerException

6.isRedefineClassesSupported()

代码如下(示例):

isRedefineClassesSupported()

同isRetransformClassesSupported,在manifest里配置的

7.redefineClasses(ClassDefinition… definitions) throws ClassNotFoundException, UnmodifiableClassException

代码如下(示例):

redefineClasses(ClassDefinition… definitions) throws  ClassNotFoundException, UnmodifiableClassException

和retransformClasses非常的相似。
retransformClasses是fix-and-continues,而redefined则是直接替换掉了。尤其是有多个agent同时工作的时候,更加推荐retransform。

8.isModifiableClass(Class theClass)

代码如下(示例):

isModifiableClass(Class theClass)

这个类是否能够被transform,如果可以则返回true

9.getAllLoadedClasses()

代码如下(示例):

getAllLoadedClasses()

获取所有被JVM加载的类,这个是诊断的好帮手

10.getInitiatedClasses(ClassLoader loader)

代码如下(示例):

getInitiatedClasses(ClassLoader loader)

获取所有被指定的classloader加载的类,如果传入null则返回由BootstrapClassl返回的类

11.getObjectSize(Object objectToSize)

代码如下(示例):

getObjectSize(Object objectToSize)

获取一个对象消耗的空间大小

12.appendToBootstrapClassLoaderSearch(JarFile jarfile)

代码如下(示例):

appendToBootstrapClassLoaderSearch(JarFile jarfile)

将指定的jar包加载给BootstrapClassLoader,可以被执行多次从而加载多个jar包。查找类的时候会先去BootStrapLoader里去找,如果找不到就到这个jar包里面去找。

需要小心处理的是,包名不要重复。例如,在ClassLoader L里加载了一个类C,他有一个私有类是C$1,如果你的jar包里正好也有个类C$1,他会先去BootstrapClassLoader里去找,发现找到了,然后去load,接着发现没有权限,就会直接报出IllegalAccessError错误。

13.appendToSystemClassLoaderSearch(JarFile jarfile)

代码如下(示例):

appendToSystemClassLoaderSearch(JarFile jarfile)

特性和appendToBootstrapClassLoader类似,不过区别是这个是用于SystemClassLoader的类的查找的(回忆一下双亲委派机制)。

14.isNativeMethodPrefixSupported()

代码如下(示例):

isNativeMethodPrefixSupported()

是否设置了本地方法的拦截,由manifest设置的。Can-Set-Native-Method-Prefix属性,具体set native method prefix的用途参考nativeMethodPrefix()

15.setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)

代码如下(示例):

appendToBootstrapClassLoaderSearch(JarFile jarfile)

对本地方法进行代码增强。但是由于本地方法是没有字节码的,所以他的办法是重新定义一个同名的函数(原来native method)的名称,然后将原来的本地方法使用prefix进行重命名。

举例,以前有一个本地方法 native boolean foo(String x),他的做法是先将native的方法重命名,例如改成
native boolean wapped_foo(String x), 然后再定义一个方法叫

boolean foo(String x) { —你的代码— ; prefix_foo(x)
}

为了防止重复,所以你的prefix最好考虑到方法重复的情况。

正常情况下,按照上面顺序执行,但是如果有问题的时候他的执行顺序分别是

method(foo) -> nativeImplementation(foo)
method(wrapped_foo) -> nativeImplementation(foo)
method(wrapped_foo) -> nativeImplementation(wrapped_foo)
method(wrapped_foo) -> nativeImplementation(foo)

二、ClassFileTransformer类

用来让用户来实现代码增强逻辑的接口。他只有一个方法,方法的参数是原来的类的字节码以及这个类的classloader对象,返回值则是被增强之后的类的字节码。所以你的代码是通过已有的类信息,植入代码之后,形成新的代码(类的字节码)。

1.transform

代码如下(示例):

transform(ClassLoader,ClassName,classBeingRedefined,protectionDomain,classfileBuffer)

这里的来源有两个,分别是Instrumentation的两个addInstrumentation()方法。
这个函数被调用的时机有如下几种情况:

  1. 这个类第一次被加载,当ClassLoader的defineClass()方法(这个方法是classloader将字节码解析成类并且放入metaspace的过程)被调用的时候,这个方法会被call
  2. Instrumentation#redefineClasses被调用了这个方法的时候,这个方法也会被调用
  3. Instrumentation#retransformClasses当这个方法被调用的时候,这个方法也会被调用
    他们的执行是按照addInstrumentation的顺序来执行的。而reTransformClasses和redefineClasses被执行的时候,他们修改的字节码是在之前已经被增强的基础上进行的。

例如原始方法是foo(String x), 然后在类加载的时候进行了一些增强,插入了一段代码,那么在下次retransformClasses执行,这个方法被调用的时候,增加的字节码是在上一次的基础上进行的。换句话说,classfileBuffer永远都是最后增强执行完成之后的版本。

关于异常和返回值。如果返回值是null,代表这次调用什么都没做,没有任何增强代码加入。他的效果和抛出异常是一样的,如果在执行这个函数的过程中抛出了异常,则代表本次调用什么都不做,和返回null值的效果是一样的。

总结

本文仅仅简单介绍了Instrumentation类的方法,具体Instrumentation的使用还需要结合Javassit开源的分析、编辑和创建Java字节码的类库,后续会继续介绍

参考文档

Instrumentation类方法简单介绍相关推荐

  1. 图像超分辨率简单介绍

    文章目录 图像超分辨率简单介绍 什么是图像超分辨率? 常见的图像超分辨率算法 插值算法 基于边缘的图像重建算法 局部线性嵌入(LLE) 拉普拉斯正则化 基于深度学习的超分辨率算法 超分辨率CNN 超分 ...

  2. perf基本使用与简单介绍

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可. 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权. 文章目录 引言 perf简单介绍 ...

  3. C#中File和FileStream的简单介绍和用法

    前言 在近期的工作过程中发现自己的基础比较薄弱,所以最近在恶补基础知识.下面就对我所学习的File类和FileStream进行简单的总结. 1.首先先介绍File类和FileStream文件流 1.1 ...

  4. 遗传算法的简单介绍以及模式定理的简单证明

    遗传算法   遗传算法(Genetic Algorithm,GA),最早是由美国的John holland在20世纪70年代提出.算法通过模拟达尔文生物进化论的自然选择以及遗传学机理的生物进化过程来搜 ...

  5. 2021年大数据ELK(十八):Beats 简单介绍和FileBeat工作原理

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Beats 简单介绍和FileBeat工作原理 一.Beats 二.FileB ...

  6. 2021年大数据ELK(十五):Elasticsearch SQL简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch SQL简单介绍 一.SQL与Elasticsear ...

  7. 2021年大数据ELK(二):Elasticsearch简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 一.Elasticsearch简介 1.介绍 2.创始人 二.E ...

  8. iOS开发UI篇—多控制器和导航控制器简单介绍

    iOS开发UI篇-多控制器和导航控制器简单介绍 一.多控制器 一个iOS的app很少只由一个控制器组成,除非这个app极其简单.当app中有多个控制器的时候,我们就需要对这些控制器进行管理 有多个vi ...

  9. 简单介绍一下R中的几种统计分布及常用模型

    统计学上分布有很多,在R中基本都有描述.因能力有限,我们就挑选几个常用的.比较重要的简单介绍一下每种分布的定义,公式,以及在R中的展示. 统计分布每一种分布有四个函数:d――density(密度函数) ...

最新文章

  1. php 正则 菜鸟,PHP正则表达式基础入门
  2. Loj #149. 01 分数规划(01分数规划模板题)
  3. 卡特兰数 HDU2067 HDU4165 HDU1134
  4. UIActionSheet的最后一项点击失效
  5. 快速配置Maven到OSChina中央库的教程
  6. Python入门:局部变量与全局变量1
  7. FISCO BCOS源码(4)第三方依赖和模块
  8. python加粗字体_Python:openpyxl将字体更改为粗体 - python
  9. 【GitHub通过ssh方法下载详细配置过程】
  10. 关于金山词霸2009牛津版在windows2003下无法对PDF文件取词的问题
  11. 工测中坐标方位角的计算c语言,工程测量中坐标方位角是怎么进行推算的?
  12. K8S Pod该如何监控
  13. 小米note2鸿蒙ROM,小米最新刷机包rom下载_奇兔rom市场
  14. MATLAB中求传递函数代码
  15. 多益网络2015校园招聘第二次笔试题
  16. 7-12 打印倒直角三角形图案
  17. php连接sqlserver数据库服务器(或者称mssql数据库)的几种方法
  18. Python入门教学
  19. 2020.5.9测试 T3 数星星
  20. 201709今日头条测试开发校招面经

热门文章

  1. 特斯拉全自动驾驶3次撞上儿童假人,撞后没停重新加速
  2. 【C语言】十六进制转十进制
  3. Veritas troubleshoots
  4. 中外文数据库助力科学研究--笔记 《2022年研究生科研素养提升》
  5. 举个栗子~Tableau 技巧(228):堆叠柱形图中同时显示类别值与总值
  6. matlab求因子载荷矩阵,Matlab因子分析
  7. 服务器运行aspx,aspx文件怎么打开?aspx是什么文件?
  8. SpringCloud升级之路2020.0.x版-43.为何 SpringCloudGateway 中会有链路信息丢失
  9. 如何使用scanf函数?
  10. 我的第一个Java项目实训--家庭记账软件!