Java Agent怎么用

Java Agent 技术简介

java agent 直译为 java 代理,也常常被称为 java 探针技术。

Java Agent 这种技术是在 JDK1.5 引入的,可以在运行时动态修改 Java 字节码。Java 中的类编译后形成字节码被 JVM 执行,在 JVM 在执行这些字节码之前获取这些字节码的信息,并且通过字节码转换器对这些字节码进行修改,以此来完成一些额外的功能。

Java Agent 是一个不能独立运行 jar 包,它通过依附于目标程序的 JVM 进程,进行工作。启动时只需要在目标程序的启动参数中添加-javaagent 参数添加 ClassFileTransformer 字节码转换器,相当于在main方法前加了一个拦截器。

Java Agent 功能介绍

Java Agent 主要有以下功能:

Java Agent 能够在加载 Java 字节码之前拦截并对字节码进行修改;

立即学习“Java免费学习笔记(深入)”;

Java Agent 能够在 Jvm 运行期间修改已经加载的字节码;

Java Agent 的应用场景:

IDE 的调试功能,例如 Eclipse、IntelliJ IDEA ;

热部署功能,例如 JRebel、XRebel、spring-loaded;

各种线上诊断工具,例如 Btrace、Greys,还有阿里的 Arthas;

各种性能分析工具,例如 Visual VM、JConsole 等;

全链路性能检测工具,例如 Skywalking、Pinpoint等;

Java Agent 实现原理

在了解Java Agent的实现原理之前,需要对Java类加载机制有一个较为清晰的认知。一种是在man方法执行之前,通过premain来执行,另一种是程序运行中修改,需通过JVM中的Attach实现,Attach的实现原理是基于JVMTI。

主要是在类加载之前,进行拦截,对字节码修改

下面我们分别介绍一下这些关键术语:

JVMTI 就是JVM Tool Interface,是 JVM 暴露出来给用户扩展使用的接口集合,JVMTI 是基于事件驱动的,JVM每执行一定的逻辑就会触发一些事件的回调接口,通过这些回调接口,用户可以自行扩展

JVMTI是实现 Debugger、Profiler、Monitor、Thread Analyser 等工具的统一基础,在主流 Java 虚拟机中都有实现

JVMTIAgent是一个动态库,利用JVMTI暴露出来的一些接口来干一些我们想做、但是正常情况下又做不到的事情,不过为了和普通的动态库进行区分,它一般会实现如下的一个或者多个函数:

Agent_OnLoad函数,如果agent是在启动时加载的,通过JVM参数设置

Agent_OnAttach函数,如果agent不是在启动时加载的,而是我们先attach到目标进程上,然后给对应的目标进程发送load命令来加载,则在加载过程中会调用Agent_OnAttach函数

Agent_OnUnload函数,在agent卸载时调用

javaagent 依赖于instrument的JVMTIAgent(Linux下对应的动态库是libinstrument.so),还有个别名叫JPLISAgent(Java Programming Language Instrumentation Services Agent),专门为Java语言编写的插桩服务提供支持的

instrument 实现了Agent_OnLoad和Agent_OnAttach两方法,也就是说在使用时,agent既可以在启动时加载,也可以在运行时动态加载。其中启动时加载还可以通过类似-javaagent:jar包路径的方式来间接加载instrument agent,运行时动态加载依赖的是JVM的attach机制,通过发送load命令来加载agent

JVM Attach 是指 JVM 提供的一种进程间通信的功能,能让一个进程传命令给另一个进程,并进行一些内部的操作,比如进行线程 dump,那么就需要执行 jstack 进行,然后把 pid 等参数传递给需要 dump 的线程来执行

Java Agent 案例

我们就以打印方法的执行时间为例,通过Java Agent 来实现。

首先我们需要构建一个精简的Maven项目,在其中构建两个Maven的子项目,一个用于实现外挂的Agent,一个用于实现测试目标程序。

Java Agent怎么用

我们在父应用中导入两个项目公共依赖的包

                        org.javassist            javassist            3.28.0-GA            

登录后复制

首先我们去构建测试的目标程序

// 启动类public class APPMain {    public static void main(String[] args) {        System.out.println("APP 启动!!!");        AppInit.init();    }}// 模拟的应用初始化的类public class AppInit {    public static void init() {        try {            System.out.println("APP初始化中...");            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

登录后复制

然后我们启动程序,测试是否能正常执行,程序正常执行之后,我们开始构建探针程序

探针程序中我们需要编写,改变原有class的Transformer,通过自定义的Transformer类完成输出方法执行时间的功能,

Java Agent怎么用

首先构检Agent程序的入口

public class RunTimeAgent {    public static void premain(String arg, Instrumentation instrumentation) {        System.out.println("探针启动!!!");        System.out.println("探针传入参数:" + arg);        instrumentation.addTransformer(new RunTimeTransformer());    }}

登录后复制

这里每个类加载的时候都会走这个方法,我们可以通过className进行指定类的拦截,然后借助javassist这个工具,进行对Class的处理,这里的思想和反射类似,但是要比反射功能更加强大,可以动态修改字节码。

javassist是一个开源的分析、编辑和创建Java字节码的类库。

import javassist.ClassPool;import javassist.CtClass;import javassist.CtMethod;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.security.ProtectionDomain;public class RunTimeTransformer implements ClassFileTransformer {    private static final String INJECTED_CLASS = "com.zhj.test.init.AppInit";    @Override    public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {        String realClassName = className.replace("/", ".");        if (realClassName.equals(INJECTED_CLASS)) {            System.out.println("拦截到的类名:" + realClassName);            CtClass ctClass;            try {                // 使用javassist,获取字节码类                ClassPool classPool = ClassPool.getDefault();                ctClass = classPool.get(realClassName);                // 得到该类所有的方法实例,也可选择方法,进行增强                CtMethod[] declaredMethods = ctClass.getDeclaredMethods();                for (CtMethod method : declaredMethods) {                    System.out.println(method.getName() + "方法被拦截");                    method.addLocalVariable("time", CtClass.longType);                    method.insertBefore("System.out.println("---开始执行---");");                    method.insertBefore("time = System.currentTimeMillis();");                    method.insertAfter("System.out.println("---结束执行---");");                    method.insertAfter("System.out.println("运行耗时: " + (System.currentTimeMillis() - time));");                }                return ctClass.toBytecode();            } catch (Throwable e) { //这里要用Throwable,不要用Exception                System.out.println(e.getMessage());                e.printStackTrace();            }        }        return classfileBuffer;    }}

登录后复制

我们需要在Maven中配置,编译打包的插件,这样我们就可以很轻松的借助Maven生成Agent的jar包

                                    org.apache.maven.plugins                maven-compiler-plugin                3.5.1                                                    8                    8                                                        org.apache.maven.plugins                maven-jar-plugin                3.2.0                                                                                                                true                                                                            1.0                            com.zhj.agent.RunTimeAgent                            true                            true                                                                                    

登录后复制

否则我们需要在resources下创建META-INF/MANIFEST.MF文件,文件内容如下,我们可以看出这个与Maven中的配置是一致的,然后通过配置编译器,借助编译器打包成jar包,需指定该文件

Manifest-Version: 1.0Premain-Class: com.zhj.agent.RunTimeAgentCan-Redefine-Classes: trueCan-Retransform-Classes: true

登录后复制

告示文件MANIFEST.MF参数说明:

Manifest-Version

文件版本

Premain-Class

包含 premain 方法的类(类的全路径名)main方法运行前代理

Agent-Class

包含 agentmain 方法的类(类的全路径名)main开始后可以修改类结构

Boot-Class-Path

设置引导类加载器搜索的路径列表。查找类的特定于平台的机制失败后,引导类加载器会搜索这些路径。按列出的顺序搜索路径。列表中的路径由一个或多个空格分开。(可选)

Can-Redefine-Classes true

表示能重定义此代理所需的类,默认值为 false(可选)

Can-Retransform-Classes true

表示能重转换此代理所需的类,默认值为 false (可选)

Can-Set-Native-Method-Prefix true

表示能设置此代理所需的本机方法前缀,默认值为 false(可选)

最后通过Maven生成Agent的jar包,然后修改测试目标程序的启动器,添加JVM参数即可

参数示例:-javaagent:F:codemyCodegent-testuntime-agentargetuntime-agent-1.0-SNAPSHOT.jar=hello

Java Agent怎么用

最终效果:

Java Agent怎么用

以上就是Java Agent怎么用的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2625946.html

(0)
上一篇 2025年3月7日 00:47:25
下一篇 2025年2月28日 07:42:29

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Java Spring怎么实现定时任务

    java实现定时任务 jdk自带的库中,有两种方式可以实现定时任务,一种是timer,另一种是scheduledthreadpoolexecutor。 Timer+TimerTask 创建一个Timer就创建了一个线程,可以用来调度Time…

    2025年3月7日
    200
  • Java 中的异构系统集成和数据集成技术

    随着大数据和云计算技术的发展,企业和组织面临着多种异构系统的集成和数据交换的挑战。在这个背景下,java 的异构系统集成和数据集成技术得到了广泛的应用和发展。本文将从异构系统集成和数据集成的概念、java 中异构系统集成和数据集成的原理和应…

    编程技术 2025年3月7日
    200
  • Java 中的移动支付和金融科技技术

    随着人们生活方式和消费习惯的变化,移动支付和金融科技在全球范围内正在迅速发展。作为一种新兴的支付方式,移动支付已经成为了人们生活中不可或缺的一部分。java 作为一种强大的编程语言,在移动支付和金融科技领域也有着重要的作用。 移动支付的核心…

    编程技术 2025年3月7日
    200
  • Java 中的区块链和数字货币技术

    区块链和数字货币技术是如今最热门的技术之一,文章将对java中的区块链和数字货币技术进行探讨。 区块链是一个由多个块组成的链式结构网络,每个块存储着许多交易信息。 在Java中,区块链可以通过使用Spring Boot和Web3J等框架来实…

    编程技术 2025年3月7日
    200
  • Java语言中的微信小程序开发介绍

    微信小程序是一种轻量级的应用程序,可以在微信平台上运行,不需要下载安装,方便快捷。java语言作为一种广泛应用于企业级应用开发的语言,也可以用于微信小程序的开发。 在Java语言中,可以使用Spring Boot框架和第三方工具包来开发微信…

    编程技术 2025年3月7日
    200
  • Java语言中的云计算应用介绍

    云计算是近年来广受关注和推崇的一种计算模式,它通过集成计算和存储资源,并通过互联网提供这些资源给用户,为企业和个人提供更加灵活、可扩展的it服务。java作为一种广泛应用于企业级开发的编程语言,也成为了云计算应用中常见的语言之一。在这篇文章…

    编程技术 2025年3月7日
    200
  • Java语言中的在线支付应用开发介绍

    随着网络技术的不断发展和普及,线上支付的需求也越来越高。作为一门广泛应用于企业级开发的编程语言,java提供了丰富的库和工具,方便开发者开发高效、安全、可维护的在线支付应用。本文将介绍java语言中的在线支付应用开发,包括相关技术、安全性和…

    编程技术 2025年3月7日
    200
  • Java语言中的Hibernate框架介绍

    hibernate是一个开放源码的orm框架,它将关系型数据库和java程序之间的数据映射相互绑定,这样可以使开发人员更方便地访问数据库中的数据。使用hibernate框架可以大量减少编写sql语句的工作,提高应用程序的开发效率和可重用性。…

    编程技术 2025年3月7日
    200
  • Java语言中的网络架构设计知识介绍

    随着互联网的迅速发展,java作为一种具有广泛应用的编程语言,成为了网络架构设计的重要组成部分。java语言拥有众多的网络应用框架和库,具有高效、安全、可靠等特性,越来越多的企业在其产品中采用java语言作为主要的技术方案。 网络架构设计,…

    编程技术 2025年3月7日
    200
  • Java语言中的在线教育应用开发介绍

    java是一种广泛应用于互联网中的编程语言,它在在线教育应用开发中具有重要的地位。在这篇文章中,我们将介绍java语言在在线教育应用开发中的作用,并提供一些实用的开发技巧。 Java在在线教育应用开发中的优点 Java语言在在线教育应用开发…

    编程技术 2025年3月7日
    200

发表回复

登录后才能评论