个人随笔
目录
一、JavaAgent:在主程序运行之前和之后的代理程序
2020-11-30 15:23:52

一、Java Agent 简介

在JDK1.5以后,我们可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能。

Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供),下面这两种我都举个例子。

二、在主程序运行之前的代理

1、构建一个代理程序

代码例子很简单,这里是用maven写的例子,如下:

  1. public class AgentTest {
  2. /**
  3. * 在主程序运行之前执行
  4. * @param agentArgs
  5. * @param isnt
  6. */
  7. public static void premain(String agentArgs,Instrumentation inst) {
  8. System.out.println("premain start");
  9. System.out.println(agentArgs);
  10. }
  11. }

在构建的时候pom中加入如下内容

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>com.suibibk</groupId>
  4. <artifactId>AgentTest</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. <packaging>jar</packaging>
  7. <build>
  8. <plugins>
  9. <plugin>
  10. <groupId>org.apache.maven.plugins</groupId>
  11. <artifactId>maven-jar-plugin</artifactId>
  12. <version>3.1.2</version>
  13. <configuration>
  14. <archive>
  15. <manifest>
  16. <addClasspath>true</addClasspath>
  17. </manifest>
  18. <manifestEntries>
  19. <Premain-Class>
  20. com.suibibk.AgentTest
  21. </Premain-Class>
  22. </manifestEntries>
  23. </archive>
  24. </configuration>
  25. </plugin>
  26. </plugins>
  27. </build>
  28. </project>

主要是

  1. <Premain-Class>
  2. com.suibibk.AgentTest
  3. </Premain-Class>

maven install构建获得jar包路径

  1. D:\Work\eclipse_workspace\AgentTest\target\AgentTest-0.0.1-SNAPSHOT.jar

2、构建一个被代理的程序

  1. public class Test2 {
  2. public static void main(String[] args) {
  3. System.out.println("main2");
  4. }
  5. }

运行时添加如下VM Arguments参数(eclipse右键Run Configurations):

  1. -javaagent:D:\Work\eclipse_workspace\AgentTest\target\AgentTest-0.0.1-SNAPSHOT.jar=haha

运行,可以发现日志为:

  1. premain start
  2. haha
  3. main2

在运行之前先执行了代理程序

三、在主程序运行之后的代理

在主程序运行之前的agent模式有一些缺陷,例如需要在主程序运行前就指定javaagent参数,premain方法中代码出现异常会导致主程序启动失败等,为了解决这些问题,JDK1.6以后提供了在程序运行之后改变程序的能力。它的实现步骤和之前的模式类似。

1、构建一个代理程序

  1. public class AgentTest {
  2. /**
  3. * 在主程序运行之后执行
  4. * @param args
  5. * @param inst
  6. */
  7. public static void agentmain(String args,Instrumentation inst) {
  8. System.out.println("loadagent after main run.args="+args);
  9. Class<?>[] classes = inst.getAllLoadedClasses();
  10. for (Class<?> cls : classes) {
  11. System.out.println(cls.getName());
  12. }
  13. System.out.println("agent run completely");
  14. }
  15. }

我们复用上面的类,将premain方法修改为agentmain方法,由于是在主程序运行后再执行,意味着我们可以获取主程序运行时的信息,这里我们打印出来主程序中加载的类名。

pom.xml改动一下,把

  1. <Premain-Class>
  2. com.suibibk.AgentTest
  3. </Premain-Class>

改为

  1. <Agent-Class>
  2. com.suibibk.AgentTest
  3. </Agent-Class>

然后构建,获得路径。

  1. D:\Work\eclipse_workspace\AgentTest\target\AgentTest-0.0.1-SNAPSHOT.jar

2、构建一个被代理程序

我这里的代理程序是一个常驻内存的web程序,也就是我的个人网站suibibk.com,当然只是本地启动,然后用cmd执行jsp -lv获取PID为:17276

3、构建一个代理与被代理程序通信的程序

在程序运行后加载,我们不可能在主程序中编写加载的代码,只能另写程序,那么另写程序如何与主程序进行通信?这里用到的机制就是attach机制,它可以将JVM A连接至JVM B,并发送指令给JVMB执行,JDK自带常用工具如jstack,jps等就是使用该机制来实现的。

  1. public class Test {
  2. public static void main(String[] args) {
  3. try {
  4. VirtualMachine vm = VirtualMachine.attach("17276");
  5. vm.loadAgent("D:\\Work\\eclipse_workspace\\AgentTest\\target\\AgentTest-0.0.1-SNAPSHOT.jar");
  6. } catch (Exception e) {
  7. e.printStackTrace();
  8. }
  9. }
  10. }

我这里刚开始会一直报错,搞不懂为什么找不到VirtualMachine类,然后一怒之下我直接去添加jdk lib目录下的tools.jar,然后就可以了。

执行该程序,发现被代理程序打印了日志:

  1. ch.qos.logback.core.spi.DeferredProcessingAware
  2. ch.qos.logback.classic.Logger
  3. ch.qos.logback.core.spi.AppenderAttachable
  4. org.slf4j.spi.LocationAwareLogger
  5. ch.qos.logback.classic.spi.LoggerContextVO
  6. ...
  7. ...
  8. java.lang.Object
  9. agent run completely

可以看到,agentmain方法中的代码已经在主程序中顺利运行了,并且打印出了程序中加载的类!

参考:https://www.jianshu.com/p/63c328ca208d

 339

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2