IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Instrumentation类方法简单介绍 -> 正文阅读

[人工智能]Instrumentation类方法简单介绍


前言

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字节码的类库,后续会继续介绍

参考文档

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 10:49:09  更:2021-08-02 10:49:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 22:22:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码