前言
要了解阿尔萨斯的底层原理需要对其涉及到知识有所了解,本文将介绍阿尔萨斯涉及到的JVMTI
、Instrumentation
、Java attach
、asm/Java assist
等几个关键点进行阐述。
什么是JVMTI
JVMTI 的全称是 JVM Tools Interface,是Java虚拟机提供的一整套后门。通过这套后门可以对虚拟机方方面面进行监控,分析,甚至干预虚拟机的运行。JVMTI 本质上是在JVM内部的许多事件进行了埋点。通过这些埋点可以给外部提供当前上下文的一些信息。它是分析工具与调试器的基础。
我的理解:在虚拟机操作过程有很多埋点,比如在VM初始化过程就埋了一个点,这个点你可以通过C/C++来对该点有一个自定义的逻辑,来干涉VM的操作。
什么是Instrumentation
虽然java提供了JVMTI,但是对应的agent需要用C/C++开发,对java开发者而言并不是非常友好。因此在Java SE 5的新特性中加入了Instrumentation机制。有了 Instrumentation,开发者可以构建一个基于Java编写的Agent来监控或者操作JVM了,比如替换或者修改某些类的定义等。
JavaAgent 的两种方式
在 Java 中实现Instrumentation有两种方式:在类执行前通过premain来执行 , 或者在启动执行后通过agentMain实现。
- premain是在 Java SE 5中新引入的 ,开发者只能在 premain 当中施展想象力,所作的 Instrumentation 也仅限与 main 函数执行前,这样的方式存在一定的局限性。
- Java SE 6 针对这种状况做出了改进,开发者可以在 main 函数开始执行以后,再启动自己的 Instrumentation 程序,这种方式通过agentMain。
Java attach
在Java SE 5中是通过指定premain所在的jar来启动虚拟机,而Java SE 6 通过发送命令到目标虚拟机,让目标虚拟机再load jar,那么这个过程比如涉及到虚拟机之间的通信。Java SE 6 就是通过Java attach 来实现两个主机之间的通信的。
ASM / Java assist
Java是软件开发人员能读懂的语言,class字节码是JVM能读懂的语言,class字节码最终会被JVM解释成机器能读懂的语言。无论哪种语言,都是人创造的。所以,理论上(实际上也确实如此)人能读懂上述任何一种语言,既然能读懂,自然能修改。只要我们愿意,我们完全可以跳过Java编译器,直接写字节码文件,只不过这并不符合时代的发展罢了,毕竟高级语言设计之始就是为我们人类所服务,其开发效率也比机器语言高很多。
对于人类来说,字节码文件的可读性远远没有Java代码高。尽管如此,还是有一些杰出的程序员们创造出了可以用来直接编辑字节码的框架,提供接口可以让我们方便地操作字节码文件,进行注入修改类的方法,动态创造一个新的类等等操作。其中最著名的框架应该就是ASM了,cglib、Spring等框架中对于字节码的操作就建立在ASM之上。
到这里,我们知道了用ASM或者Java assist框架直接操作class文件,在类中加一段打印日志的代码,然后调用retransformClasses就可以了。