Java探针 Instrumentation

article/2025/9/21 0:54:44

背景:假如我们想打印出某些系统->某些类->某些方法的执行耗时,方式有很多,但是想要无侵入的做到这一点,只有Java探针一种方式。这也是很多调用链系统依赖的技术基础。

什么是Java探针

通俗来讲,就是Java提供的一种手段,使我们可以修改并重新加载Class字节码,做到在系统外部来改变类的行为。

Java探针是如何做到的

我们知道只要是java程序,运行的入口就一定是main方法。Java探针技术相当于变相的改变了这个约定,提供了一种外挂,只要用了这个外挂(即在程序的运行时参数中加了-javaagent),就可以先执行外挂jar包中的premain方法,然后再执行原程序中的main方法。这样就提供了一个在真正的程序执行前,可以修改并重新加载字节码的机会。

具体怎么做

我们写个demo。

  1. 假如原程序为:

    public class DemoMain {public static void main(String[] args) {System.out.println("\nDemoMain.main开始");HelloService helloService = new HelloService();helloService.sayHello("一拳超人");System.out.println("DemoMain.main结束");}}public class HelloService {public void sayHello(String name) {System.out.println("      HelloService.sayHello开始");System.out.println("         Hello " + name + "!");System.out.println("      HelloService.sayHello结束");}}
    
  2. 打jar包,新版的idea打包配置有点小问题,默认的MANIFEST的文件夹路径中,要删除/main/java,如图:

  1. 我们想打印HelloService.sayHello的执行耗时,使用Java探针来实现,先写外挂程序

```java
public class PrintAgent {public static void premain(String agentArgs, Instrumentation instrumentation) {System.out.println("\nPrintAgent.premain开始");System.out.println("   PrintAgent.premain入参:" + agentArgs);instrumentation.addTransformer(new PrintTransformer());System.out.println("PrintAgent.premain结束");}public static void main(String[] args) {//main方法在idea打包时需要,实际上没什么作用,不会被执行。}}public class PrintTransformer implements ClassFileTransformer {final static String startTime = "\nlong startTime = System.nanoTime();\n";final static String endTime = "\nlong endTime = System.nanoTime();\n";final static Map<String, List<String>> methodMap = new HashMap<String, List<String>>();public PrintTransformer() {addMethod("com.wang.hello.HelloService", "sayHello");}private PrintTransformer addMethod(String className, String methodName) {List<String> list = methodMap.computeIfAbsent(className, cn -> new ArrayList<>());list.add(methodName);return this;}@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {className = className.replace("/", ".");if (methodMap.containsKey(className)) {try {CtClass ctClass = ClassPool.getDefault().get(className);for (String methodName : methodMap.get(className)) {String cost = "\nSystem.out.println(\"   Method:"+ methodName+ " Cost:\"+(endTime-startTime)+"+ "\"ns\");\n";CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);String wrappedMethodName = methodName + "$wrapped";ctMethod.setName(wrappedMethodName);CtMethod newMethod = CtNewMethod.copy(ctMethod, methodName, ctClass, null);StringBuilder newMethodBody = new StringBuilder();newMethodBody.append("{");newMethodBody.append(startTime);newMethodBody.append(wrappedMethodName + "($$);\n");newMethodBody.append(endTime);newMethodBody.append(cost);newMethodBody.append("}");newMethod.setBody(newMethodBody.toString());ctClass.addMethod(newMethod);}return ctClass.toBytecode();} catch (Exception e) {e.printStackTrace();}}return null;}
}
```
  1. PrintAgent的打包配置如图:

16191343861365.jpg

  1. 然后需要修改PrintAgent的META-INF/MANIFEST.MF文件,改为(注意结尾必须加一新行):

    Manifest-Version: 1.0
    Premain-Class: com.wang.agent.PrintAgent
    Can-Redefine-Classes: true
    **我是空白行占位符**
    
  2. 打完包后,我们就可以执行测试了,先看下原始程序打印的日志:

    //执行java -jar demo.jar
    DemoMain.main开始HelloService.sayHello开始Hello 一拳超人!HelloService.sayHello结束
    DemoMain.main结束
    
  3. 外挂探针后,再次执行打印的日志,注意其中"Method:sayHello Cost:128835ns"为我们增加的耗时日志:

    //执行java -javaagent:instrumentation.jar=wahaha -jar demo.jar
    PrintAgent.premain开始PrintAgent.premain入参:wahaha
    PrintAgent.premain结束DemoMain.main开始HelloService.sayHello开始Hello 一拳超人!HelloService.sayHello结束Method:sayHello Cost:128835ns
    DemoMain.main结束
    
  4. 关键的点解决后,再往深了做,就能慢慢的实现调用链的逻辑了。

扫描下方公众号二维码 免费领取125套简历模板 👇👇👇


http://chatgpt.dhexx.cn/article/KPseqSgA.shtml

相关文章

opentelemetry-java-instrumentation翻译

原文地址&#xff1a;原文 OpenTelemetry Instrumentation for Java 这个项目提供了一个Java agent JAR&#xff0c;这个jar可以attached to任何Java8的应用上&#xff0c;动态地注入&#xff08;inject&#xff09;字节码从大量的流行库和框架&#xff08;popular libraries …

Instrument

使用Instruments 里面的Automation&#xff0c;可以对iOS进行自动化测试。 参考这篇文章&#xff1a;http://www.codeproject.com/KB/iPhone/UI_Automation_Testing.aspx 我用的是xcode4.2。 在这里下载修改好的项目&#xff0c;xcode4.2下用的&#xff1a;http://download.csd…

android Instrumentation

Android提供了一系列强大的测试工具&#xff0c;它针对Android的环境&#xff0c;扩展了业内标准的JUnit测试框架。尽管你可以使用JUnit测试Android工程&#xff0c;但Android工具允许你为应用程序的各个方面进行更为复杂的测试&#xff0c;包括单元层面及框架层面。 Android测…

Instrumentation 应用简介

引用&#xff1a; java-instrumentation 引用&#xff1a;Instrumentation 新功能 简介 java Instrumentation指的是可以用独立于应用程序之外的代理&#xff08;agent&#xff09;程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态&#…

AndroidStudio单元测试——instrumentation

前言&#xff1a;这几天老大要我搞代码自动测试&#xff0c;eclispe的已经解决了&#xff0c;可他们都是用android studio&#xff0c;所以要在android studio 上重新试验&#xff0c;这个有难度啊&#xff0c;android studio国内资料极少&#xff0c;更不要说单元测试了。goog…

Android Instrumentation 简介

Instrumentation 简介 APIs && Source code 官方APIs地址(需要翻墙)Source code Instrumentation 特点 该框架基于JUnit&#xff0c;因此既可以直接使用Junit 进行测试&#xff0c;也可以使用Instrumentation 来测试Android 组件其为Android 应用的每种组件提供了测…

冲突域和广播域?

如何理解冲突域和广播域&#xff1f; 冲突域&#xff1a; 【定义】在同一个冲突域中的每一个节点都能收到所有被发送的帧。简单的说就是同一时间内只能有一台设备发送信息的范围。 【分层】基于OSI的第一层物理层 【设备】第二层设备能隔离冲突域&#xff0c;比如Switch。交…

广播域与冲突域

广播域与冲突域 一个集线器&#xff08;中继器&#xff09;连接的网络成为冲突域&#xff0c;因为每台主机都连接在了同一条线路上&#xff0c;所以传送信息时会冲突。 冲突域是基于第一层(物理层) 而交换机的本质是一个多借口网桥&#xff0c;就是说由交换机组成的网络中&…

冲突域广播域

网络互连设备可以将网络划分为不同的冲突域、广播域。但是&#xff0c;由于不同的网络互连设备可能工作在OSI模型的不同层次上。因此&#xff0c;它们划分冲突域、广播域的效果也就各不相同。如中继器工作在物理层&#xff0c;网桥和交换机工作在数据链路层&#xff0c;路由器工…

广播域和冲突域问题

该图中有几个冲突域几个广播域&#xff1f; 解答&#xff1a; 1、两个广播域&#xff0c;七个冲突域。 这样的&#xff1a;集线器属于物理层&#xff0c;所有接口同属于一个冲突域、一个广播域&#xff1b;交换机属于数据链路层&#xff0c;每个接口是一个单独的冲突域…

冲突域和碰撞域的理解

如何理解冲突域和广播域&#xff1f; 转载 冲突域&#xff1a; 【定义】在同一个冲突域中的每一个节点都能收到所有被发送的帧。简单的说就是同一时间内只能有一台设备发送信息的范围。 【分层】基于OSI的第一层物理层 【设备】第二层设备能隔离冲突域&#xff0c;比如Swi…

如何计算冲突域和广播域-图解分析

如何理解冲突域和广播域?冲突域:【定义】在同一个冲突域中的每一个节点都能收到所有被发送的帧。简单的说就是同一时间内只能有一台设备发送信息的范围。【分层】基于OSI的第一层(数据链路层)物理层【设备】第二层设备能隔离冲突域,比如Switch。交换机能缩小冲突域的范围,交…

有关冲突域的定义

一开始学习网络的时候&#xff0c;对于冲突域和广播域的理解仅仅是从设备上进行理解的&#xff0c;即集线器是一个冲突域&#xff0c;交换机能够分离冲突域&#xff0c;不能够分离广播域&#xff0c;路由器可以分离组播域。至于冲突域到底是什么&#xff0c;怎么样定义的&#…

如何辨别数清冲突域和广播域

1、首先&#xff0c;须知第一层不能隔离冲突域和广播域。例如集线器或者直接连PC 2、其次&#xff0c;第二层可以隔离冲突域&#xff0c;但不能隔离广播域。例如&#xff0c;二层交换机 3、接着&#xff0c;第三层可以隔离广播域&#xff0c;默认隔离冲突域&#xff0c;例如&…

详解广播域和冲突域的区别

总览 1、广播域可以跨网段&#xff0c;而冲突域只是发生的同一个网段的。以太网中&#xff0c;冲突域是由hub组织的。一个hub就是一个冲突域。交换机的每个端口都是一个冲突域。网段&#xff0c;又叫潜在冲突域。 2、冲突域在同一个冲突域中的每一个节点都能收到所有被发送的…

冲突域

一、冲突域 一个站点向另一个站点发出信号&#xff0c;除目的站点外&#xff0c;有多少站点能收到这个信息&#xff0c;这些站点就构成一个冲突域。在同一个冲突域中的每个节点都能收到所有被发送的帧&#xff0c;冲突域是基于第一层&#xff08;物理层&#xff09;。 传统共享…

collision domain - 冲突域

英文&#xff1a; Collision Domain 中文&#xff1a; 冲突域 介绍&#xff1a; 不同主机或设备同时发出的帧可能会互相冲突的网络区域。一条导线上所有工作站的集合&#xff0c;或一个物理网段上所有节点的集合&#xff0c;或以太网上竞争同一带宽的节点的集合都是一个冲突域…

Java 程序员开发常用的工具

1、常用开发工具 2、常用接口测试工具 3、常用远程连接工具 4、一些其他常用工具 5、总结 1、常用开发工具 作为一名Java程序开发人员&#xff0c;可以的选择集成开发环境IDE&#xff08;Integrated Development Environment&#xff09;非常多&#xff0c;得益于Java是一门开…

java编程软件(一) idea

前段时间&#xff0c;有个学弟问我OJ的题目&#xff0c;本来这是一件很正常的事情。 主要是关注点不是那道OJ题&#xff0c;而是他编程所使用的软件———blueJ。既熟悉又陌生的名字。 BlueJ在编写的过程是很不方便的&#xff0c;当然&#xff0c;在类与类之间的关系倒是能很好…

学java编程需要安装什么软件?

近几年学编程的同学或者想学习编程的同学越来越多&#xff0c;提到编程java语言肯定是里面的佼佼者&#xff0c;今天小千就来给大家介绍一下学Java编程都需要安装什么软件&#xff0c;自学的同学有福了。 1.java环境 想要从事Java开发&#xff0c;那么Java运行环境肯定是你首先…