「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇
相关历史文章(阅读本文之前,您可能需要先看下之前的系列????)国内最全的SpringBoot系列之三100G的文件如何读取续集-第307篇Java语言的优雅停机-第308篇SpringBoot优雅停止服务的几种方法-第309篇Docker优雅的关闭SpringBoot-第310篇「字节码插桩」统计方法耗时(第一篇:初出茅庐)-第311篇师傅:今天我们就扒开JavaAgent来看看,到底是何方神圣
相关历史文章(阅读本文之前,您可能需要先看下之前的系列👇)
SpringBoot 优雅停止服务的几种方法 - 第309篇
「字节码插桩」统计方法耗时(第一篇:初出茅庐)- 第311篇
师傅:今天我们就扒开JavaAgent来看看,到底是何方神圣。
徒儿:师傅扒的好。
师傅:恩赫…. 徒儿这波脑洞可以哦。
徒儿:那是师傅用词让人产生误解。
师傅:你是杠精吧,杠不过你。
一、何为字节码插桩
我们知道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编写一个可以统计耗时的呐,我们下节揭晓。
更多推荐
所有评论(0)