「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇
一、何为字节码插桩
我们知道JVM是不能直接执行.java 代码,也不能直接执行.class文件,它只能执行.class 文件中存储的指令码。这就是为什么class需要通过classLoader 装载以后才能运行。基于此机制可否在ClassLoader装载之前拦截修改class当中的内容(jvm 指令码)从而让程序中包含我们的埋点逻辑呢? 答案是肯定的,但需要用到两个技术 javaagent与javassist 。前者用于拦截ClassLoad装载,后者用于操作修改class文件。
二、javaagent
2.1 javaagent介绍
javaagent 是java1.5之后引入的特性,其主要作用是在class 被加载之前对其拦截,以插入我们的监听字节码
2.2 javaagent jar包
javaagent 最后展现形式是一个Jar包,有以下特性:
1)必须 META-INF/MANIFEST.MF中指定Premain-Class 设定启agent启动类。
2)在启类需写明启动方法 public static void main(String arg,)
3)不可直接运行,只能通过 jvm 参数-javaagent:xxx.jar 附着于其它jvm 进程运行。
三、javaagent使用
3.1 编写agent方法
新建一个项目,然后新建一个Agent类:
- package com.kfit;
- import java.lang.instrument.Instrumentation;
-
- public class MyAgent {
- /**
- * jvm 参数形式启动,运行此方法
- *
- * @param agentArgs
- * @param inst
- */
- public static void premain(String agentArgs, Instrumentation inst) {
- System.out.println("Hello javaagent permain:"+agentArgs);
- }
-
- /**
- * 动态 attach 方式启动,运行此方法
- *
- * @param agentArgs
- * @param inst
- */
- public static void agentmain(String agentArgs, Instrumentation inst) {
- System.out.println("Hello javaagent agentmain");
- }
- }
对于Agent有两种使用方式:
jvm 参数形式:调用 premain 方法
attach 方式:调用 agentmain 方法
其中 jvm 方式,也就是说要使用这个 agent 的目标应用,在启动的时候,需要指定 jvm 参数 -javaagent:xxx.jar,当我们提供的 agent 属于基础必备服务时,可以用这种方式
当目标应用程序启动之后,并没有添加-javaagent加载我们的 agent,依然希望目标程序使用我们的 agent,这时候就可以使用 attach 方式来使用。
在接下来我们讲解下jvm参数的配置方式。
3.2 添加premain-class参数
在pom.xml文件添加如下配置:
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>2.2</version>
- <configuration>
- <archive>
- <manifestEntries>
- <Project-name>${project.name}</Project-name>
- <Project-version>${project.version}</Project-version>
- <Premain-Class>com.kfit.MyAgent1</Premain-Class>
- <Can-Redefine-Classes>true</Can-Redefine-Classes>
- <Can-Retransform-Classes>true</Can-Retransform-Classes>
- </manifestEntries>
- </archive>
- <skip>true</skip>
- </configuration>
- </plugin>
参数说明:
Premain-Class:必填,agent启动
classCan-Redefine-Classes:默认为false ,是否允许重新定义
classCan-Retransform-Classes:默认为false,是否允许重置Class,重置后相当于class 从classLoade中清除,下次有需要的时候会重新装载,也会重新走Transformer 流程。
Boot-Class-Path:agent 所依赖的jar 路径,多个用空格分割(这个配置我们之后使用到)
3.3 构建打包
使用maven的clean package打包出来一个jar文件:
agentdemo-0.0.1-SNAPSHOT.jar
3.4 使用agent
在任一JAVA应用中 添加jvm 参数并启动:
-javaagent:/data/tmp/agentdemo-0.0.1-SNAPSHOT.jar=angel
对于我们之前的那个MeiMei类,不需要修改任何代码,配置vm options就可以启动看下效果:
Hello javaagent permain:angel
shopping:出发去和美眉一起逛街购物!
shopping:和美眉一起回家!
花了多少钱:5000.0
看到打印结果没有,确实我们的这个main方法在执行之前打印出来了我们的那个代码。那么怎么使用javaagent编写一个可以统计耗时的呐,我们下节揭晓。
购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287