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

 

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

国内最全的Spring Boot系列之三

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

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

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

Docker优雅的关闭SpringBoot - 第310篇

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

 

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

徒儿:师傅扒的好。

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

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

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

 

一、何为字节码插桩

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

悟纤 CSDN认证博客专家 Spring Spring Boot
「公众号SpringBoot」:
①阿里巴巴前高级研发工程师;②估值20亿美金的Blued架构师;③北京知远公司创始人;④浙江甄才公司架构师;⑤云课堂学员10000+;⑥博客访问量1000万+;⑦10年互联网行业从业;⑧340万的访问《从零开始学SprngBoot》作者;⑨技术加盟多个独立项目。
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页
实付 19.89元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值