大家好,我是严叔叔。跟随严叔叔每天进步一点点,了解更多测试开发技术!
1、什么是Java代理? Java代理本质上可以理解为一个插件,是一个精心提供的但启动方式与普通jar包不同的jar包。
对于常规Jar包,首先指定类的main函数。然而,Java代理不能独立启动,必须运行在Java应用程序中,而Java应用程序广泛应用于面向方面的编程中。
通过JVMTI(JVM Tools Interface)加载Java代理jar包,最终借助JPLISAgent(JavaProgramming Language Instrumentation Services Agent)完成目标代码的修改。主要特点是:
您可以在加载Java文件之前拦截并修改字节码。
加载类的字节码可能会在运行时改变
比如我们目前用过的Jcoco、Arthas、Chaosblade等,都采用了Java代理技术。
2、Java Agent开发开发环境: 选择IDEA作为编辑器,Maven进行包管理
2.1 核心逻辑创建一个新项目(或子模块)并创建一个新的SimpleAgent 类。
我们快速看一下这两种方法的区别,评论中也提到了这些区别。
jvm参数格式:调用premain方法。 Attach方法:调用jvm方法所在的agentmain方法。这意味着要使用此代理的目标应用程序,您必须在启动时指定jvm 参数-javaagent:xxx.jar。然后,在执行main函数之前,JVM会执行-javaagent指定的jar包中类Premain-Class的premain方法。即在运行主程序之前启动代理。目标应用程序启动后,使用动态附加方法启动代理。这时候就可以使用attach方法了。
2.2 打包上面的简单的SimpleAgent就完成了agent核心功能的创建(很简单)。接下来我们需要创建一个Jar包。 Maven插件可以轻松输出兼容的Java代理包。有两种常见用途。
a. pom指定如何配置。
将以下设置添加到您的pom.xml 文件中。请注意manifestEntries 标记中的参数。
然后使用mvn Assembly: assembly 命令进行打包。目标目录下会出现一个后缀为jar-with-dependency的jar包。这就是目的。
b.MANIFEST.MF配置文件方法
使用配置文件MANIFEST.MF 可能更常见。在这里,我们简单说明一下使用位置。
– 在资源目录(Resources)中创建一个新目录META-INF。 – 在META-INF 目录中创建一个新文件MANIFEST.MF,内容如下:
请注意,想法需要在最后一行有一个空行。如果删除最后一行,您将收到以下错误消息:
接下来,您需要相应地更改pom.xml 设置。
同样通过mvn Assembly: assembly命令打包
2.3 使用代理现在我们已经有了代理,下面我们将讨论上面建议的两种方法。
JVM参数
首先,创建一个新的演示项目并创建一个简单的测试类。
在测试类中,每秒都会调用print 方法。您可以将jvm 参数直接添加到您的配置类中,如下所示:
注意VM选项的内容是之前打包的agent :的绝对地址。
-javaagent:D:\\web\\agenttest\\target\\agen-test-1.0-SNAPSHOT-jar-with-dependency.jar 当您运行main 方法时,您将看到控制台输出。
注意上面的premain。这是在执行主程序的main 函数之前首先执行代理的premain 函数的内容。
附加方法
如果使用Attach 方法,可以简单理解为向目标应用程序注入代理,则必须自己编写程序来完成此操作,并创建一个新的AttachMain 类。
接下来,首先启动目标应用程序。即运行demo工程中BaseMain的main函数。接下来,使用jps -l 获取目标应用程序的进程号。
将代理的AttachMain 类中的目标应用程序进程号更改为当前BaseMain 进程号20956。
运行AttachMain将代理注入到目标应用程序中,并在演示项目中的BaseMain的main函数中运行控制台。可以看到agent项目中SimpleAgent类下的agentmain函数中的代码正在运行。
2.4. 高级:替换目标程序返回的内容。创建一个简单的类TransClass,它可以通过静态方法返回整数。
修改TransClass的getNumber方法,返回2。
再次运行main函数,将class文件编译成Java文件,返回2:TransClass.class。
将此TransClass.class 复制到您的代理项目。
接下来,将一个新类添加到您的代理项目中。 Transformer 类:该类实现ClassFileTransformer 接口。
getBytesFromFile方法根据文件名读取二进制字符流,并通过ClassFileTransformer指定的转换方法完成类定义的替换和转换。
在Premain类中,在instrumentation代理方法premain下面添加代码:inst.addTransformer(new Transformer())
正如您所看到的,addTransformer 方法没有指定要转换的类。
转换发生在执行premain 函数之后和执行main 函数之前。在这种情况下,每次加载类时,都会执行一次transform方法来检查是否需要进行转换。
因此,在Transformer类的transform方法中,程序使用className.equals(\”TransClass\”)来判断当前类是否需要进行变换。
测试验证:
演示工程执行TransClass的main方法时,返回1。
将JVM 代理参数添加到您的配置类中。
再次运行TransClass的main方法,会看到返回了agent内容,并且值变成了2。
至此,我们已经完成了使用Java代理替换目标程序返回内容的演示。
总结:以上就是我这次分享的内容了。
什么是Java代理? 如何轻松开发代理开发后如何进阶使用代理:如何使用代理替换目标程序接口返回的内容===============================如果以上有帮助的话,
欢迎来到VX 搜索。关注我的公众号程序员颜叔,了解更多测试相关信息。
本文和图片来自网络,不代表火豚游戏立场,如若侵权请联系我们删除:https://www.huotun.com/game/583592.html