前言
在上一篇中,我们采用了Java SE 5 中的premain实现对虚拟机层面上的AOP,开发者只能在 premain 当中施展想象力,所作的 Instrumentation 也仅限与 main 函数执行前,这样的方式存在一定的局限性。
Java SE 6 针对这种状况做出了改进,开发者可以在 main 函数开始执行以后,再启动自己的 Instrumentation 程序,这种方式通过agentMain。本文就来记录一下如何通过agentMain的实现方式,具体细节大家可以看文章后的参考文章。
agentMain编写
1 | public class IAgentMain { |
在premain的时候,我们不需要去指定哪些类需要retransformer,因为大多数的类还没被加载如内存,加载内存的后类会经过ClassFileTransformer的转换的。
而在agentmain方式中,这里是在程序启动后,再发送指令到目标虚拟机上,这个过程之前类已经到内存了,所以是不会经过ClassFileTransformer,所以需要通过inst.retransformClasses来告诉虚拟机哪些类需要重新transformer,这样它就能经过ClassFileTransformer的转换了。
pom.xml
注意与premain类似,需要添加上Agent-Class来指定IAgentMain:
1 | <Premain-Class>agent.agentDomain.IPreMain</Premain-Class> |
pom.xml全部内容在后文。
ITransformer 编写
这个编写与premain是一样的:
1 | public class ITransformer implements ClassFileTransformer { |
Main 编写
同样这个方法与premain是一样的:
1 | public class Main { |
JVMAttach 编写
注意!!这个方法通过pid连接到目标虚拟机,通知它加载agent的jar包。VirtualMachine需要将jdk目录下的tools.jar添加到工程中,不然导入不了该类,具体操作大家可以参看参考文章。
1 | public class JVMAttach { |
先运行Main函数,是正常的输出:
再运行JVMAttach,通知运行Main函数的虚拟机去加载agent,这个agent通过编写ClassFileTransformer逻辑,对agent.Main方法进行transformer改变其类字节码,运行结果:
可以看到类的方法的确按照我们的逻辑进行了加强!!