项目总结:java agent的使用

news2025/2/19 11:32:58

测试团队会做java agent的事,实现测试模拟,各种数据采集等等工作,而这些不需要开发改代码来做到,只需要挂载下agent。

目录

    • javaagent认识和例子代码
      • 例子:
      • java.lang.instrument
      • 自定义实现一个javaagent
      • agent jar测试
    • 回顾javaagent的作用
    • 项目中用到agent的例子

javaagent认识和例子代码

例子:

java -javaagent:/Users/mubi/git_workspace/common1/common-test/target/common-test-1.0-SNAPSHOT-jar-with-dependencies.jar com.test.AgentTest

在这里插入图片描述

不改变代码,而是在java命令后加入-javaagent:xx.jar实现对class的干预

java.lang.instrument

https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html

Provides services that allow Java programming language agents to instrument programs running on the JVM.

即在Java编程语言中,允许Java代理(Agents)进行代码插装(Instrumentation)的服务主要由Java Agent API提供。这个API允许开发者在运行时动态修改或增强Java应用程序的字节码,而无需修改源代码或重新编译。这对于性能监控、调试、安全增强等场景非常有用。

自定义实现一个javaagent

  • MyAgent
package com.test;

import java.lang.instrument.Instrumentation;

/**
 * @Author mubi
 * @Date 2025/2/11 21:45
 */
public class MyAgent {
    /**
     * jvm 参数形式启动,运行此方法
     *
     * @param agentArgs agentArgs 是我们启动 Java Agent 时带进来的参数,比如-javaagent:xxx.jar agentArgs
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("premain");
        customLogic(inst);
    }

    /**
     * 动态 attach 方式启动,运行此方法
     *
     * @param agentArgs
     * @param inst
     */
    public static void agentmain(String agentArgs, Instrumentation inst) {
        System.out.println("agentmain");
        customLogic(inst);
    }

    /**
     * 打印所有已加载的类名称 修改字节码
     *
     * @param inst
     */
    private static void customLogic(Instrumentation inst) {
        inst.addTransformer(new MyTransformer(), true);
    }
}

  • 使用javaassist改变class文件
package com.test;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

/**
 * javassist 官方文档:http://www.javassist.org/tutorial/tutorial.html
 */
public class MyTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
//        System.out.println("正在加载类:" + className);
        if (!"com/test/Hello".equals(className)) {
            return classfileBuffer;
        }
        CtClass cl = null;
        try {
            ClassPool classPool = ClassPool.getDefault();
            cl = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));

            CtMethod ctMethod = cl.getDeclaredMethod("test");
            System.out.println("获取方法名称:" + ctMethod.getName());
            // 声明本地变量
            ctMethod.addLocalVariable("start", CtClass.longType);
            ctMethod.addLocalVariable("end", CtClass.longType);

            ctMethod.insertBefore("System.out.println(\" 动态插入的打印语句 \");");
            ctMethod.insertBefore("start = System.currentTimeMillis();");
            // $_在Javassist中是一个特殊的变量,代表当前正在处理的类或方法中的表达式
            ctMethod.insertAfter("System.out.println($_);");
            ctMethod.insertAfter("end = System.currentTimeMillis();");
            // 输出耗时
            ctMethod.insertAfter("System.out.println((end-start) + \" ms\");");
            byte[] transformed = cl.toBytecode();
            return transformed;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classfileBuffer;
    }
}
  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>common1</artifactId>
        <groupId>com.container</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>common-test</artifactId>

    <repositories>

    </repositories>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>attached</goal>
                        </goals>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <configuration>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <archive>
                                <manifestEntries>
                                    <Premain-Class>com.test.MyAgent</Premain-Class>
                                    <Agent-Class>com.test.MyAgent</Agent-Class>
                                    <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                    <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                </manifestEntries>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

    <properties>
        <spring.verson>5.1.3.RELEASE</spring.verson>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.27.0-GA</version>
        </dependency>

        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>9.2</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>9.2</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

</project>

即加入:

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-assembly-plugin</artifactId>
     <version>2.5.5</version>
     <executions>
         <execution>
             <goals>
                 <goal>attached</goal>
             </goals>
             <id>make-assembly</id>
             <phase>package</phase>
             <configuration>
                 <descriptorRefs>
                     <descriptorRef>jar-with-dependencies</descriptorRef>
                 </descriptorRefs>
                 <archive>
                     <manifestEntries>
                         <Premain-Class>com.test.MyAgent</Premain-Class>
                         <Agent-Class>com.test.MyAgent</Agent-Class>
                         <Can-Redefine-Classes>true</Can-Redefine-Classes>
                         <Can-Retransform-Classes>true</Can-Retransform-Classes>
                     </manifestEntries>
                 </archive>
             </configuration>
         </execution>
     </executions>
 </plugin>

按照要求:

An agent JAR file may have both the Premain-Class and Agent-Class attributes present in the manifest. When the agent is started on the command-line using the -javaagent option then the Premain-Class attribute specifies the name of the agent class and the Agent-Class attribute is ignored. Similarly, if the agent is started sometime after the VM has started, then the Agent-Class attribute specifies the name of the agent class (the value of Premain-Class attribute is ignored).

一个代理 JAR 文件可能在清单中同时具有 Premain-Class 和 Agent-Class 属性。 当使用 -javaagent 选项在命令行上启动代理时,Premain-Class 属性指定代理类的名称,而 Agent-Class 属性将被忽略。 同样,如果代理在 VM 启动后的某个时间启动,则 Agent-Class 属性指定代理类的名称(忽略 Premain-Class 属性的值)

打包生成agent jar

在这里插入图片描述

agent jar测试

定义Hello类

package com.test;

import java.util.concurrent.TimeUnit;

/**
 * @Author mubi
 * @Date 2025/2/11 23:20
 */
public class Hello {
    public String test() {
        try {
            TimeUnit.SECONDS.sleep(1);
            System.out.println("hello logic");
        } catch (Exception e) {

        }
        return "hello test";
    }
}

测试类并加上agent参数-javaagent:/Users/mubi/git_workspace/common1/common-test/target/common-test-1.0-SNAPSHOT-jar-with-dependencies.jar

在这里插入图片描述

测试输出如下:

在这里插入图片描述
即完成了代理行为。

回顾javaagent的作用

JVM启动后,JVM会执行指定Agent类的premain()方法,在premain()中可以调用Instrumentation对象的addTransformer方法注册ClassFileTransformer。当JVM加载类时会将类文件的字节数组传递给ClassFileTransformer的transform方法,在transform方法中对Class文件进行解析和修改,之后JVM就会加载转换后的Class文件。

这样实例化后执行代理了的方法就能完成,因为class文件被改过且加载好了。

在这里插入图片描述

项目中用到agent的例子

当一个入口流程开始后,可能因为不同的输入,执行了不同的链路。业务如果有扩展,那么就需要是否有执行,以及执行情况。

如下 AppProcess的entry方法 的入参不同,调用的扩展点实现也是不同,通过java agent 可以采集到信息
在这里插入图片描述

  • 主程序
package com.pro.biz;

import java.util.ArrayList;
import java.util.List;

public class AppProcess {

    /**
     * 扩展点
     */
    List<StrService> strServiceList;


    public AppProcess() {
        strServiceList = new ArrayList<>();
    }

    public void setStrServiceList(){
        strServiceList.add(new X());
        strServiceList.add(new Y());
    }

    public void entry(String name) {
        String s = null;
        if (name.equals("one")) {
            s = strServiceList.get(0).dealStr(name);
            System.out.println("entry:" + s);
            return;
        }
        if (name.equals("all")) {
            for (StrService strService : strServiceList) {
                s = strService.dealStr(name);
                System.out.println("entry:" + s);
            }
            return;
        }
    }
}
  • 扩展点和实现类
    在这里插入图片描述

  • Agent类

package com.pro.agent;

import java.lang.instrument.Instrumentation;

/**
 * @Author mubi
 * @Date 2025/2/12 22:54
 */
public class StatAgent {
    /**
     * jvm 参数形式启动,运行此方法
     *
     * @param agentArgs agentArgs 是我们启动 Java Agent 时带进来的参数,比如-javaagent:xxx.jar agentArgs
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst) {
//        System.out.println("premain");
        customLogic(inst);
    }

    /**
     * 动态 attach 方式启动,运行此方法
     *
     * @param agentArgs
     * @param inst
     */
    public static void agentmain(String agentArgs, Instrumentation inst) {
//        System.out.println("agentmain");
        customLogic(inst);
    }

    /**
     * 打印所有已加载的类名称 修改字节码
     *
     * @param inst
     */
    private static void customLogic(Instrumentation inst) {
        inst.addTransformer(new StatTransformer(), true);
    }
}

package com.pro.agent;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

/**
 * @Author mubi
 * @Date 2025/2/12 22:55
 */
public class StatTransformer implements ClassFileTransformer {


    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
//        if (!"com/pro/biz/AppProcess".equals(className)) {
//            return classfileBuffer;
//        }
        CtClass cl = null;
        try {
            ClassPool classPool = ClassPool.getDefault();
            cl = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));

            CtMethod ctMethod = null;
            try{
                ctMethod = cl.getDeclaredMethod("dealStr");
            }catch (Exception e){

            }
            if(ctMethod != null && !className.equals("com/pro/biz/StrService")) {
//                System.out.println("获取到方法名称:" + ctMethod.getName());
//                System.out.println(className);

//                ctMethod.insertBefore("System.out.println(\"入参: \" + $1);");
//                ctMethod.insertAfter("System.out.println(\"出参: \" + $_);");

                ctMethod.insertAfter(
                        "com.pro.stat.StrServiceCallStats.addCallInfo($0.getClass().getName(), $1, $_);"
                );

//                StringBuilder methodBody = new StringBuilder();
//                methodBody.append("{")
//                        .append("System.out.println(\"Input: \" + $1);") // input parameter
//                        .append("$r = $proceed($$);") // proceed with the original method
                        .append("System.out.println(\"Output: \" + result);") // output
//                        .append("return $r;")
//                        .append("}");
//
//                // Modify the method
//                ctMethod.setBody(methodBody.toString());


            }
            // 插入统计代码
//            String insertBeforeCode = "{ $_ = $proceed($$); " +
//                    "StrServiceCallStats.addCallInfo($0.strServiceList.get($index).getClass().getName(), $1, $_); }";
//            entryMethod.insertBefore(insertBeforeCode);

            byte[] transformed = cl.toBytecode();
            return transformed;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classfileBuffer;
    }
}

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>common1</artifactId>
        <groupId>com.container</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>common-project</artifactId>


    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>attached</goal>
                        </goals>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <configuration>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <archive>
                                <manifestEntries>
                                    <Premain-Class>com.pro.agent.StatAgent</Premain-Class>
                                    <Agent-Class>com.pro.agent.StatAgent</Agent-Class>
                                    <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                    <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                </manifestEntries>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

    <properties>
        <spring.verson>5.1.3.RELEASE</spring.verson>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.29.0-GA</version>
        </dependency>

        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>9.2</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>9.2</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

</project>

打包后生成agent jar, 运行时加上-javaagent:/Users/mubi/git_workspace/common1/common-project/target/common-project-1.0-SNAPSHOT-jar-with-dependencies.jar

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何借助NoETL指标平台实现数据分析、决策的提效?

通常&#xff0c;企业通过明确分析目标、定位所需分析的数据&#xff0c;再通过多渠道汇集销售数据、客户反馈、市场调研等信息&#xff0c;经过数据清洗、缺失值处理及格式标准化等手段&#xff0c;运用描述性统计、回归分析、聚类分析及关联规则挖掘等多样分析方法&#xff0…

大模型语言简介

大模型语言能做什么 信息提取 将长段文字中的信息抽取出来并且以结构化的方式输出。相比起传统NLP的方式&#xff0c;大模型在泛化能力上有非常大的提升&#xff0c;并且开发成本要低2个数量级。应用场景包括&#xff1a;论文论点论据提取、用户画像提取、舆情分析、病例结构…

手动配置IP

手动配置IP&#xff0c;需要考虑四个配置项&#xff1a; 四个配置项 IP地址、子网掩码、默认网关、DNS服务器 IP地址&#xff1a;格式表现为点分十进制&#xff0c;如192.168.254.1 子网掩码&#xff1a;用于区分网络位和主机位 【子网掩码的二进制表达式一定是连续的&#…

Golang 进阶训练营

一、Golang 的 slice、map、channel 1.1 slice vs array a : make([]int, 100) //切片 b : [100]int{} //数组array需指明长度&#xff0c;长度为常量且不可改变 array长度为其类型中的组成部分&#xff08;给参数为长度100的数组的方法传长度为101的会报错&#xff09; array在…

2-使用wifidog实现portal

wifidog是openwrt上面实现portal认证的一个开源工具&#xff0c;从网关端到服务器都帮你搭建好&#xff0c;通过学习wifidog的原理&#xff0c;后面就可以改造成自己需要的逻辑。 1. openwrt安装wifidog 添加源 vim 14.07/feeds.conf.defaultsrc-git wifidog https://github.c…

AI时代前端开发的创造力:解放还是束缚?

在人工智能&#xff08;AI&#xff09;快速发展的时代&#xff0c;AI技术的影响已经渗透到各个领域&#xff0c;从医疗保健到金融服务&#xff0c;再到创意产业。AI工具的出现&#xff0c;为前端开发带来了前所未有的效率提升&#xff0c;但也引发了人们对创造力的担忧&#xf…

有哪些免费的SEO软件优化工具

随着2025年互联网的不断发展&#xff0c;越来越多的企业意识到在数字营销中&#xff0c;网站的曝光度和排名至关重要。无论是想要提高品牌知名度&#xff0c;还是想要通过在线销售增加收益&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;都是一项不可忽视的关键策略。而要…

FastExcel + Java:打造高效灵活的Excel数据导入导出解决方案

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 基于AOP的数据字典实现…

node.js + html调用ChatGPTApi实现Ai网站demo(带源码)

文章目录 前言一、demo演示二、node.js 使用步骤1.引入库2.引入包 前端HTML调用接口和UI所有文件总结 前言 关注博主&#xff0c;学习每天一个小demo 今天是Ai对话网站 又到了每天一个小demo的时候咯&#xff0c;前面我写了多人实时对话demo、和视频转换demo&#xff0c;今天…

STM32+Proteus+DS18B20数码管仿真实验

1. 实验准备 硬件方面&#xff1a; 了解 STM32 单片机的基本原理和使用方法&#xff0c;本实验可选用常见的 STM32F103 系列。熟悉 DS18B20 温度传感器的工作原理和通信协议&#xff08;单总线协议&#xff09;。数码管可选用共阴极或共阳极数码管&#xff0c;用于显示温度值。…

Vulhub靶机 ActiveMQ 反序列化漏洞(CVE-2015-5254)(渗透测试详解)

一、开启vulhub环境 docker-compose up -d 启动 docker ps 查看开放的端口 漏洞版本&#xff1a;Apache ActiveMQ 5.x ~ Apache ActiveMQ 5.13.0 二、访问靶机IP 8161端口 默认账户密码 admin/admin&#xff0c;登录 此时qucues事件为空 1、使用jmet-0.1.0-all.jar工具将…

2025年二级建造师报名流程图解

2025年二级建造师报名时间&#xff01;附报名流程&#xff01; ⏰️已公布25年二建考试时间的省份如下&#xff1a; ️4月19日、20日考试的城市有&#xff1a;贵州 ️5月10日、11日考试的城市有&#xff1a;湖北、陕西、宁夏、甘肃、福建、浙江、江西、黑龙江、河南、湖南、…

hexo 魔改 | 修改卡片透明度

hexo 魔改 | 修改卡片透明度 ** 博客食物用更佳 博客地址 ** 这是笔者自己瞎倒腾的。作为前端菜鸡一枚&#xff0c;大佬们随便看看就好~ 我用的主题是 butterfly 4.12.0 分析 通过开发者工具可以看出来卡片的背景和 --card-bg 变量有关 再在 sources 下的 css 文件夹下的…

Golang的并发编程案例详解

Golang的并发编程案例详解 一、并发编程概述 并发编程是指程序中有多个独立的执行线索&#xff0c;并且这些线索在时间上是重叠的。在 Golang 中&#xff0c;并发是其核心特性之一&#xff0c;通过 goroutine 和 channel 来支持并发编程&#xff0c;使得程序可以更高效地利用计…

策略模式-小结

总结一下看到的策略模式&#xff1a; A:一个含有一个方法的接口 B:具体的实行方式行为1,2,3&#xff0c;实现上面的接口。 C:一个环境类&#xff08;或者上下文类&#xff09;&#xff0c;形式可以是&#xff1a;工厂模式&#xff0c;构造器注入模式&#xff0c;枚举模式。 …

硬件学习笔记--41 电磁兼容试验-5 射频场感应的传导干扰试验介绍

目录 电磁兼容试验-射频场感应的传导干扰试验介绍 1.试验目的 2.试验方法 3.判定依据及意义 电磁兼容试验-射频场感应的传导干扰试验介绍 驻留时间是在规定频率下影响量施加的持续时间。被试设备&#xff08;EUT&#xff09;在经受扫频频带的电磁影响量或电磁干扰的情况下&a…

泛型 类 接口 方法 通配符

泛型 泛型类 what: 类型参数化 why use&#xff1a; 1. 输出时候是object类型 而不是真正类型转化麻烦 import java.util.ArrayList; import java.util.List;public class ObjectExample {public static void main(String[] args) {List<Object> list new ArrayLi…

文字转语音(三)FreeTTS实现

项目中有相关的功能&#xff0c;就简单研究了一下。 说明 FreeTTS 是一个基于 Java 的开源文本转语音&#xff08;TTS&#xff09;引擎&#xff0c;旨在将文字内容转换为自然语音输出。 FreeTTS 适合对 英文语音质量要求低、预算有限且需要离线运行 的场景&#xff0c;但若需…

STM32 RTC 实时时钟说明

目录 背景 RTC(实时时钟)和后备寄存器 32.768HZ 如何产生1S定时 RTC配置程序 第一次上电RTC配置 第1步、启用备用寄存器外设时钟和PWR外设时钟 第2步、使能RTC和备份寄存器访问 第3步、备份寄存器初始化 第4步、开启LSE 第5步、等待LSE启动后稳定状态 第6步、配置LSE为…