当前位置: 首页 > news >正文

字节码编程之bytebuddy结合javaagent支持多种监控方式

写在前面

打印方法执行耗时是监控,获取程序运行的JVM信息是监控,链路追踪也是监控。

本文看下如何实现一个通用的监控解决方案。

1:程序

定义premain:

package com.dahuyou.multi.monitor;import com.dahuyou.multi.monitor.factory.PluginFactory;
import com.dahuyou.multi.monitor.linktrace.LinkTraceAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;import java.lang.instrument.Instrumentation;
import java.util.List;public class MyPreMain {public static void premain(String agentArgs, Instrumentation inst) {System.out.println("Java agent配置参数:" + agentArgs);System.out.println("============================");System.out.println("大忽悠🐂B监控系统开始工作了!");System.out.println("============================");AgentBuilder agentBuilder = new AgentBuilder.Default();// 获取所有可用的监控插件(jvm,链路追踪,执行耗时等)List<IPlugin> pluginGroup = PluginFactory.pluginGroup;for (IPlugin plugin : pluginGroup) {InterceptPoint[] interceptPoints = plugin.buildInterceptPoint();for (InterceptPoint point : interceptPoints) {AgentBuilder.Transformer transformer= (builder, typeDescription, classLoader, javaModule) -> {builder = builder.visit(Advice.to(plugin.adviceClass()).on(point.buildMethodsMatcher()));return builder;};agentBuilder = agentBuilder.type(point.buildTypesMatcher()).transform(transformer).asDecorator();}}// 将bytebuddy的插桩逻辑安装到instrumentagentBuilder.with(new AgentBuilder.Listener() {@Overridepublic void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {}@Overridepublic void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
//                System.out.println("onTransformation:" + typeDescription);}@Overridepublic void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {}@Overridepublic void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {}@Overridepublic void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {}}).installOn(inst);}
}

这里将不同的监控类型抽象为插件,定义了监控插件接口类:

package com.dahuyou.multi.monitor.plugin;/*** 监控插件接口*/
public interface IPlugin {/*插件名称*/String pluginName();/*插件的监控点(即监控哪些类的哪些方法)*/InterceptPoint[] buildInterceptPoint();/*执行具体监控的切面类*/Class adviceClass();}

本文实现,打印JVM,和链路追踪两种监控方式,实现类如下:

package com.dahuyou.multi.monitor.plugin.concrete;import com.dahuyou.multi.monitor.jvmusage.JVMUsageAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;/*** jvm使用情况插件*/
public class JvmPlugin implements IPlugin {@Overridepublic String pluginName() {return "jvmusage";}@Overridepublic InterceptPoint[] buildInterceptPoint() {return new InterceptPoint[]{new InterceptPoint() {@Overridepublic ElementMatcher<TypeDescription> buildTypesMatcher() {return ElementMatchers.nameStartsWith("com.dahuyou.multi.monitor");}@Overridepublic ElementMatcher<MethodDescription> buildMethodsMatcher() {return ElementMatchers.named("method1").or(ElementMatchers.named("method2")).or(ElementMatchers.named("method3"));}}};}@Overridepublic Class adviceClass() {return JVMUsageAdvice.class;}}
package com.dahuyou.multi.monitor.plugin.concrete;import com.dahuyou.multi.monitor.jvmusage.JVMUsageAdvice;
import com.dahuyou.multi.monitor.linktrace.LinkTraceAdvice;
import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.InterceptPoint;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;/*** 链路追踪插件*/
public class LinkTracePlugin implements IPlugin {@Overridepublic String pluginName() {return "linktrace";}@Overridepublic InterceptPoint[] buildInterceptPoint() {return new InterceptPoint[]{new InterceptPoint() {@Overridepublic ElementMatcher<TypeDescription> buildTypesMatcher() {return ElementMatchers.nameStartsWith("com.dahuyou.multi.monitor");}@Overridepublic ElementMatcher<MethodDescription> buildMethodsMatcher() {return ElementMatchers.named("method1").or(ElementMatchers.named("method2")).or(ElementMatchers.named("method3"));}}};}@Overridepublic Class adviceClass() {return LinkTraceAdvice.class;}}

通过插件工厂PluginFactory来维护所有可用的监控插件:

package com.dahuyou.multi.monitor.factory;import com.dahuyou.multi.monitor.plugin.IPlugin;
import com.dahuyou.multi.monitor.plugin.concrete.JvmPlugin;
import com.dahuyou.multi.monitor.plugin.concrete.LinkTracePlugin;
import java.util.ArrayList;
import java.util.List;/*** 可用监控插件工厂类*/
public class PluginFactory {public static List<IPlugin> pluginGroup = new ArrayList<>();static {//链路追踪监控pluginGroup.add(new LinkTracePlugin());//Jvm监控插件pluginGroup.add(new JvmPlugin());}}

接口InterceptPoint,用来抽象监控点,接口定义如下:

package com.dahuyou.multi.monitor.plugin;import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;/*** 插件监控点接口,设置插件要监控的类和要监控的方法*/
public interface InterceptPoint {/*设置插件要监控的类*/ElementMatcher<TypeDescription> buildTypesMatcher();/*设置插件要监控的方法*/ElementMatcher<MethodDescription> buildMethodsMatcher();}

核心逻辑就是这些了,详细的大家感兴趣的话还是看源码。

接着来打包:
在这里插入图片描述
测试类:

package com.dahuyou.multi.monitor.test;public class ApiTest {public static void main(String[] args) {//线程一new Thread(() -> new ApiTest().method1(), "线程思密达").start();
//        new Thread(() -> new ApiTest().method1(), "线程萨瓦迪卡").start();//        new ApiTest().method1();}public void method1() {System.out.println("测试结果:hi1");method2();}public void method2() {System.out.println("测试结果:hi2");method3();}public void method3() {System.out.println("测试结果:hi3");}}

配置javaagent:
在这里插入图片描述
运行测试:
在这里插入图片描述

写在后面

参考文章列表

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Spring全家桶系列之核心篇 | Spring Cloud】 - 第七章 掌握Gateway核心技术,实现高效路由与转发
  • 灵雀云AML:赋能金融AI,构建数智时代核心竞争力
  • Android SurfaceView 组件介绍,挖洞原理详解
  • Apache httpd-vhosts.conf 配置详解(附Demo)
  • 【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十一)-无人机服务可用性用例需求
  • 不常用的第三方服务集成
  • [米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-22 TPG图像测试数据发生器设计
  • CSS实现从上往下过渡效果
  • 【算法基础】Dijkstra 算法
  • 乘积量化pq:将高维向量压缩 97%
  • SSM 整合(Spring + MyBatis;Spring + Spring MVC)
  • VUE中setup()
  • Python爬虫速成之路(3):下载图片
  • 【常见开源库的二次开发】基于openssl的加密与解密——Base的编解码(二进制转ascll)(二)
  • 1219:马走日
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 【剑指offer】让抽象问题具体化
  • express如何解决request entity too large问题
  • HTTP那些事
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • js面向对象
  • js中的正则表达式入门
  • linux学习笔记
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • MD5加密原理解析及OC版原理实现
  • Terraform入门 - 3. 变更基础设施
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 再谈express与koa的对比
  • ​Spring Boot 分片上传文件
  • #php的pecl工具#
  • (1)svelte 教程:hello world
  • (39)STM32——FLASH闪存
  • (k8s中)docker netty OOM问题记录
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (转)四层和七层负载均衡的区别
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • (转载)虚函数剖析
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • 、写入Shellcode到注册表上线
  • .Net IOC框架入门之一 Unity
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net流程开发平台的一些难点(1)
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • [ 转载 ] SharePoint 资料
  • [16/N]论得趣
  • [Android]一个简单使用Handler做Timer的例子
  • [BZOJ4337][BJOI2015]树的同构(树的最小表示法)
  • [c++] 单例模式 + cyberrt TimingWheel 单例分析
  • [dfs] 图案计数
  • [go-zero] 简单微服务调用
  • [Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句
  • [java]删除数组中的某一个元素
  • [LitCTF 2024]exx
  • [Machine Learning] Learning with Noisy Labels
  • [PAT练级笔记] 44 Basic Level 1044 火星数字