JVM代理

  • 介绍

我们都知道Java工程可以打包成为可运行的jar文件(其实就是一个zip压缩格式的压缩包),而这个jar文件里会包含META-INF/MANIFEST.MF——指定要从哪个类中的main方法来启动。

如果想要在执行这个main方法之前先执行一段逻辑怎么办呢?这里提供一种不修改源码的方式:javaagent。

  • 测试类

直接上代码吧:

和main方法类似地,我们这里有一个premain方法,而且还能接受参数(inst参数由JVM传递)。另外,premain方法还可以定义为下面的方式(优先级低):

public static void premain(String agentArgs)

好吧,这个类还是需要在manifest中加以描述才可以的。

玩Java的人都知道,这个奇怪的manifest文件中,最后一行必须是空行。

一切就绪,只欠东风了,通过命令行来启动试试:

java -javaagent:a.jar=surenpi.com -jar newtalk.jar

需要注意的是,javaagent这个参数必须在jar参数之前,而且还可以有多个。

  • 类替换

上面的内容只是介绍了如何在jar文件运行前执行一段代码,这并不能对现有的jar文件中的代码造成什么影响。下面要说的是:我们需要把newtalk.jar中的类文件(class)替换掉。哈哈,现在开始有点意思了吧。

还记得上面的Instrumentation吗,我们可以通过这个接口,在JVM加载类的时候“偷梁换柱”。这里纯粹是为了效果演示哦,通过查看上面的newtalk.jar中的manifest文件可以看到,里面会有一个启动类org.suren.talk.TalkGate。好的,我们就把这个类给替换掉,下面是它的替身:

恩,又被你发现了,我们这里的替身啥事情也不做,只是打印一句话而已。那“偷梁换柱”的这种脏活让谁来做呢?

本文隐藏内容 登陆 后才可以浏览

上面的逻辑非常简单,就是在加载对应的类时,读取另外一个类文件(要和原来的类的签名一样哦)并返回字节码数组。

最后呢,要在我们的premain方法中再添加一句非常关键的内容:

inst.addTransformer(new TestClassFileTransformer());

  • 参考

这里提到的代理,不是设计模式中的那种代理,如果想了解更多Java代理的内容,请看这里

发表评论

电子邮件地址不会被公开。 必填项已用*标注