快速学习Java Agent

1.1 java agent原理

我们知道,要使用Skywalking去监控服务,需要在其 VM 参数中添加 “-
javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar"。这里就 使用到了java agent技术。

Java agent 是什么?

Java agent是java命令的一个参数。参数 javaagent 可以用于指定一个 jar 包。

  1. 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。
  2. Premain-Class 指定的那个类必须实现 premain() 方法。

当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行 -javaagent所指定 jar 包内 Premain- Class 这个类的 premain 方法 。

如何使用java agent?
使用 java agent 需要几个步骤:

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-Redefine- Classes 和 Can-Retransform-Classes 选项。
  2. 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
  3. 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
  4. 使用参数 -javaagent: jar包路径 启动要代理的方法。

1.1.1 搭建java agent工程

使用maven创建java_agent_demo工程

快速学习-Skywalking原理_C

在java文件夹下新建PreMainAgent类

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class PreMainAgent {

        /**
     * 在这个 premain 函数中,开发者可以进行对类的各种操作。
     * 1、agentArgs 是 premain 函数得到的程序参数,随同 “– javaagent”一起传入。与 main 函数不同的是,
     * 这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。
     * 2、Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。*
     * java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,
     * 集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
     * @param agentArgs
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("=========premain方法执行1========");
        System.out.println(agentArgs);
    }

    /**
     * 如果不存在 premain(String agentArgs, Instrumentation inst)
     * 则会执行 premain(String agentArgs)
     * @param agentArgs
     */
    public static void premain(String agentArgs) {
        System.out.println("=========premain方法执行2========");
        System.out.println(agentArgs);
    }
}

类中提供两个静态方法,方法名均为premain,不能拼错

在pom文件中添加打包插件

<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <!--自动添加META-INF/MANIFEST.MF -->
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                        <manifestEntries>
                            <Premain-Class>PreMainAgent</Premain-Class>
                            <Agent-Class>PreMainAgent</Agent-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

该插件会在自动生成META-INF/MANIFEST.MF文件时,帮我们添加agent相关的配置信息。 使用maven的package命令进行打包:

快速学习-Skywalking原理_C_02

打包成功之后,复制打包出来的jar包地址

快速学习-Skywalking原理_jar_03

1.1.2 搭建主工程

使用maven创建java_agent_user工程

快速学习-Skywalking原理_C_04

Main


public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

先运行一次,然后点击编辑MAIN启动类

快速学习-Skywalking原理_maven_05

在VM options中添加代码

快速学习-Skywalking原理_C_06

代码为

-javaagent:路径\java-agent-demo-1.0-SNAPSHOT.jar=HELLOAGENT

启动时加载javaagent,指向上一节中编译出来的java agent工程jar包地址,同时在最后追加参数 HELLOAGENT。
运行MAIN方法,查看结果:

快速学习-Skywalking原理_java_07

可以看到java agent的代码优先于MAIN函数的方法运行,证明java agent运行正常

1.1.3 统计方法调用时间

Skywalking中对每个调用的时长都进行了统计,这一小节中我们会使用ByteBuddy和Java agent技术来 统计方法的调用时长。

Byte Buddy是开源的、基于Apache 2.0许可证的库,它致力于解决字节码操作和instrumentation API 的复杂性。Byte Buddy所声称的目标是将显式的字节码操作隐藏在一个类型安全的领域特定语言背 后。通过使用Byte Buddy,任何熟悉Java编程语言的人都有望非常容易地进行字节码操作。Byte Buddy提供了额外的API来生成Java agent,可以轻松的增强我们已有的代码。

添加依赖:

<dependencies>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy-agent</artifactId>
            <version>1.9.2</version>
        </dependency>
</dependencies>

修改PreMainAgent代码

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import java.lang.instrument.Instrumentation;

public class PreMainAgent {

    public static void premain(String agentArgs, Instrumentation inst) {
        //创建一个转换器,转换器可以修改类的实现
        //ByteBuddy对java agent提供了转换器的实现,直接使用即可
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
                return builder
                        // 拦截任意方法
                        .method(ElementMatchers.<MethodDescription>any())
                        // 拦截到的方法委托给TimeInterceptor
                        .intercept(MethodDelegation.to(MyInterceptor.class));
            }
        };
        new AgentBuilder // Byte Buddy专门有个AgentBuilder来处理Java Agent的场景
                .Default()
                // 根据包名前缀拦截类
                .type(ElementMatchers.nameStartsWith("com.agent"))
                // 拦截到的类由transformer处理
                .transform(transformer)
                .installOn(inst);
    }
}

先生成一个转换器,ByteBuddy提供了java agent专用的转换器。通过实现Transformer接口利用 builder对象来创建一个转换器。转换器可以配置拦截方法的格式,比如用名称,本例中拦截所有方 法,并定义一个拦截器类

MyInterceptor。

创建完拦截器之后可以通过Byte Buddy的AgentBuilder建造者来构建一个agent对象。AgentBuilder可 以对指定的包名前缀来生效,同时需要指定转换器对象。

import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MyInterceptor {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable<?> callable)
            throws Exception {
        long start = System.currentTimeMillis();
        try {
            //执行原方法
            return callable.call();
        } finally {
            //打印调用时长
            System.out.println(method.getName() + ":" + (System.currentTimeMillis() - start)  + "ms");
        }
    }
}

MyInterceptor就是一个拦截器的实现,统计的调用的时长。参数中的method是反射出的方法对象,而 callable就是调用对象,可以通过callable.call()方法来执行原方法。

重新打包,执行maven package命令。接下来修改主工程代码。主工程将Main类放置到 com.agent包 下。修改代码内容为:

Main


public class Main {
    public static void main(String[] args) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hello World");
    }
}

休眠1秒,使统计时长的演示效果更好一些。执行main方法之后显示结果

快速学习-Skywalking原理_jar_08

我们在没有修改代码的情况下,利用java agent和Byte Buddy统计出了方法的时长,Skywalking的 agent也是基于这些技术来实现统计调用时长。

1.2 Open Tracing介绍

OpenTracing通过提供平台无关、厂商无关 的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。OpenTracing中最核心的概念就是 Trace。

1.2.1 Trace的概念

在广义上,一个trace代表了一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准 中,trace是多个span组成的一个有向无环图(DAG),每一个span代表trace中被命名并计时的连续性 的执行片段。

快速学习-Skywalking原理_C_09

例如客户端发起的一次请求,就可以认为是一个Trace。将上面的图通过Open Tracing的语义修改完之 后做可视化,得到下面的图

快速学习-Skywalking原理_C_10

图中每一个色块其实就是一个span

1.2.2 Span的概念

一个Span代表系统中具有开始时间和执行时长的逻辑运行单元。span之间通过嵌套或者顺序排列建立 逻辑因果关系。

Span里面的信息包括:操作的名字,开始时间和结束时间,可以附带多个 key:value 构成的 Tags(key 必须是String,value可以是 String, bool 或者数字),还可以附带 Logs 信息(不一定所有的实现都支持) 也是 key:value形式。
下面例子是一个 Trace,里面有8个 Span:

快速学习-Skywalking原理_maven_11

一个span可以和一个或者多个span间存在因果关系。OpenTracing定义了两种关系: ChildOf 和 FollowsFrom。这两种引用类型代表了子节点和父节点间的直接因果关系。未来,OpenTracing将支 持非因果关系的span引用关系。(例如:多个span被批量处理,span在同一个队列中,等等)

ChildOf 很好理解,就是父亲 Span 依赖另一个孩子 Span。比如函数调用,被调者是调用者的孩子,比 如说 RPC 调用,服务端那边的Span,就是 ChildOf 客户端的。很多并发的调用,然后将结果聚合起来 的操作,就构成了 ChildOf 关系。

如果父亲 Span 并不依赖于孩子 Span 的返回结果,这时可以说它他构成 FollowsFrom 关系。

快速学习-Skywalking原理_maven_12

如图所示,左边的每一条追踪代表一个Trace,而右边时序图中每一个节点就是一个Span。

1.2.3 Log的概念

每个span可以进行多次Logs操作,每一次Logs操作,都需要一个带时间戳的时间名称,以及可选的任 意大小的存储结构。
如下图是一个异常的Log:

快速学习-Skywalking原理_java_13

如下图是两个正常信息的Log,它们都带有时间戳和对应的事件名称、消息内容

快速学习-Skywalking原理_C_14

1.2.4 Tags的概念

每个span可以有多个键值对(key:value)形式的Tags,Tags是没有时间戳的,支持简单的对span进行 注解和补充。

如下图就是一个Tags的详细信息,其中记录了数据库访问的SQL语句等内容。

快速学习-Skywalking原理_jar_15

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/241575.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python tkiinter中滑块的使用

需求&#xff1a;需要在Canvas组件上添加滑块功能 解决&#xff1a;使用tkinter提供的Scrollbar组件&#xff0c;由于没发现直接在画布上显示滑块功能的方法&#xff0c;所以后面采用在显示画布的容器上显示滑块&#xff0c;并绑定到画布上。 具体案例demo&#xff1a; from t…

视频滤波驱动器电路D1671 D1675的性能描述和分析

D1671四阶标清视频滤波器驱动&#xff0c;1CH&#xff0c;工作电压2.8V~5.5V&#xff0c;转换速率40V/s D1675六阶高清视频滤波器驱动&#xff0c;1CH&#xff0c;工作电压2.5V~5.5V&#xff0c;转换速率400V/s

02鸿蒙APP真机运行及证书签名打包

目录 1、真机运行1.1、运行安装错误1.2、解决方案&#xff1a;第一步&#xff1a;安装兼容真机的sdk版本2.2.0&#xff08;API6&#xff09;&#xff0c;如下图所示&#xff1a;第二步&#xff1a;新建一个API6的工程项目第三步&#xff1a;运行API6创建的工程项目第四步&#…

如何提高嵌入式软件工程师的技术深度?

今日话题&#xff0c;如何提高嵌入式软件工程师的技术深度&#xff1f;建立坚实的基础知识是深入研究的关键。只有深入理解基础知识&#xff0c;才能在理论指导下不断深化和扩展自己的技术。没有坚实的基础&#xff0c;深入研究就显得空中楼阁。如果你有兴趣进入嵌入式行业我可…

数据库——安全性

智能2112杨阳 一、目的与要求&#xff1a; 1、设计用户子模式 2、根据实际需要创建用户角色及用户&#xff0c;并授权 3、针对不同级别的用户定义不同的视图&#xff0c;以保证系统的安全性 二、内容&#xff1a; 先创建四类用户角色&#xff1a; 管理员角色Cusm、客户角…

初级数据结构(三)——栈

文中代码源文件已上传&#xff1a;数据结构源码 <-上一篇 初级数据结构&#xff08;二&#xff09;——链表 | 初级数据结构&#xff08;四&#xff09;——队列 下一篇-> 1、栈的特性 1.1、函数栈帧简述 即使是刚入门几天的小白&#xff0c;对栈这个字…

Linux——MySQL数据库系统()

一、访问MySQL数据库 MySQL数据库系统也是一个典型的C/S(客户端/服务器&#xff09;架构的应用&#xff0c;要访问MySQL数据库需要使用专门的客户端软件。在Linux系统中&#xff0c;最简单、易用的MySQL客户端软件是其自带的mysql命令工具。 1、登录到MySQL服务器经过安装后的初…

深入理解TheadLocal的使用场景和注意事项

前言 在日常实际开发当中我们往往会看到项目中有使用 ThreadLocal 的场景&#xff0c;大多数人有时候可能涉及不到自己的业务则没有进行关注。通常我在看代码时对于一些未知的东西常常引起我的好奇&#xff0c;我往往会分析&#xff1a;为什么要这么做&#xff1f;好处是什么&…

一文看懂支付前链路流程

一文看懂支付前链路流程 前序 首先支付流程讲究的就是快&#xff0c;还有就是订单的冲入&#xff0c;我们不能说一笔交易订单进来都加一个分布式锁去解决&#xff0c;所以我们目前常用的做法就是一个订单进来&#xff0c;首先落库&#xff0c;如果落库失败&#xff0c;并且是…

用XAMPP在Windows系统构建一个本地Web服务器

用XAMPP在Windows系统构建一个本地Web服务器 Build a Local Web Server for Windows with XAMPP By JacksonML 本文简要介绍如何获取和安装XAMPP以实现Windows环境下本地Web服务器的过程&#xff0c;希望对广大网友和学生有所帮助。 所谓本地Web服务器&#xff0c;即使用本地…

UML-认识6种箭头(画类图无烦恼)

文章目录 一、背景二、箭头详解2.1 泛化&#xff08;Generalization&#xff09;2.2 实现&#xff08;Realize&#xff09;2.3 依赖&#xff08;Dependency&#xff09;2.4 关联&#xff08;Association&#xff09;2.5 聚合&#xff08;Aggregation&#xff09;2.6 组合&#…

24V降12V2A同步降压芯片WT6023A

24V降12V2A同步降压芯片WT6023A 今天给大家带来一款高性能的DC/DC转换器WT6023A&#xff0c;快来一起了解一下吧&#xff01; WT6023A是一款采用抖动频率模式控制架构的高效、单片同步降压型DC/DC转换器&#xff0c;能够提供高达6A的连续负载&#xff0c;具有出色的线路和负载…

BugKu-Web-Flask_FileUpload(模板注入与文件上传)

Flask Flask是一个使用Python编写的轻量级Web应用框架。它是一个微型框架&#xff0c;因为它的核心非常简单&#xff0c;但可以通过扩展来增加其他功能。Flask的核心组件包括Werkzeug&#xff0c;一个WSGI工具箱&#xff0c;以及Jinja2&#xff0c;一个模板引擎。 Flask使用BSD…

快速准确翻译文件夹名:英文翻译成中文,文件夹批量重命名的技巧

在处理大量文件夹时&#xff0c;可能会遇到要将英文文件夹名翻译成中文的情况。同时也可能要批量重命名这些文件夹。今天一起来看下云炫文件管理器如何快速准确翻译文件夹名&#xff0c;进行批量重命名的技巧。 下图是文件夹名翻译前后的效果图。 英文文件夹名批量翻译成中文…

注意力机制和自注意力机制

有很多自己的理解&#xff0c;仅供参考 Attention注意力机制 对于一张图片&#xff0c;我们第一眼看上去&#xff0c;眼睛会首先注意到一些重点的区域&#xff0c;因为这些区域可能包含更多或更重要的信息&#xff0c;这就是注意力机制&#xff0c;我们会把我们的焦点聚焦在比…

2023年12月7日:QT实现登陆界面

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//窗口设置this->resize(600,500);//重新设置窗口大小this->setWindowTitle("QQ-盗版");//设置窗口名为QQ-盗版this->setWindowIcon(QIcon("D:\\Qt\\funny\\pi…

【改进YOLOv8】融合感受野注意力卷积RFCBAMConv的杂草分割系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着计算机视觉技术的不断发展&#xff0c;图像分割成为了一个重要的研究领域。图像分割可以将图像中的不同对象或区域进行有效的分离&#xff0c;对于许多应用领…

【广州华锐视点】仓储物流3D数字孪生平台打造更高效、智能的物流管理体验

在当今快速发展的物流行业中&#xff0c;传统的管理和监控方法往往难以满足复杂运营的需求。为了解决这个问题&#xff0c;广州华锐互动提供仓储物流3D数字孪生平台定制开发服务&#xff0c;打造更为高效、智能的物流管理体验。 仓储物流3D数字孪生平台是一种基于虚拟现实技术的…

DNS漫游指南:从网址到IP的奇妙之旅

当用户在浏览器中输入特定网站时发生的整个端到端过程可以参考下图 1*4vb-NMUuYTzYBYUFSuSKLw.png 问题&#xff1a; 什么是 DNS&#xff1f; 答案 → DNS 指的是域名系统&#xff08;Domain Name System&#xff09;。DNS 是互联网的目录&#xff0c;将人类可读的域名&#…

flutter 代码混淆

Flutter 应用混淆&#xff1a; Flutter 应用的混淆非常简单&#xff0c;只需要在构建 release 版应用时结合使用 --obfuscate 和 --split-debug-info 这两个参数即可。 –obfuscate --split-debug-info 用来指定输出调试文件的位置&#xff0c;该命令会生成一个符号映射表。目前…