「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇

「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇_第1张图片

 

相关历史文章(阅读本文之前,您可能需要先看下之前的系列

国内最全的Spring Boot系列之三

100G的文件如何读取续集 - 第307篇

Java语言的优雅停机 - 第308篇

SpringBoot 优雅停止服务的几种方法 - 第309篇

Docker优雅的关闭SpringBoot - 第310篇

「字节码插桩」统计方法耗时(第一篇:初出茅庐)- 第311篇

 

师傅:今天我们就扒开JavaAgent来看看,到底是何方神圣。

「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇_第2张图片

徒儿:师傅扒的好。

师傅:恩赫…. 徒儿这波脑洞可以哦。

徒儿:那是师傅用词让人产生误解。

师傅:你是杠精吧,杠不过你。

「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇_第3张图片

 

一、何为字节码插桩

我们知道JVM是不能直接执行.java 代码,也不能直接执行.class文件,它只能执行.class 文件中存储的指令码。这就是为什么class需要通过classLoader 装载以后才能运行。基于此机制可否在ClassLoader装载之前拦截修改class当中的内容(jvm 指令码)从而让程序中包含我们的埋点逻辑呢? 答案是肯定的,但需要用到两个技术 javaagentjavassist 。前者用于拦截ClassLoad装载,后者用于操作修改class文件。

 

二、javaagent

2.1 javaagent介绍

javaagent 是java1.5之后引入的特性,其主要作用是在class 被加载之前对其拦截,以插入我们的监听字节码

「字节码插桩」统计方法耗时(第二篇:崭露头角)- 第312篇_第4张图片

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文件添加如下配置:

	
				org.apache.maven.plugins
				maven-jar-plugin
				2.2
				
					
						
							${project.name}
							${project.version}
							com.kfit.MyAgent1
							true
							true
						
					
					true
				

参数说明:

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编写一个可以统计耗时的呐,我们下节揭晓。

你可能感兴趣的:(从零开始学Spring,Boot,spring,boot,java,spring,spring,boot)