javaagent使用

news/2024/9/23 20:20:07/

Java Agent是什么?

在这里插入图片描述

Java Agent是Java平台提供的一个强大工具,它可以在运行时修改或增强Java应用程序的行为。是在JDK1.5以后引入的,它能够在不影响正常编译的情况下修改字节码,相当于是在main方法执行之前的拦截器,也叫premain,也就是会先执行premain方法然后再执行main方法。
使用javaagent可以用于执行一个jar包,并且对这个java包有两个要求:

  • jar包的MANIFEST.MF文件必须指定Premain-Class项
  • Premain-Class指定的那个类必须实现premain()方法
    当程序启动的时候,JVM会首先检查-javaagent所指定的jar包内Premain-Class这个类中的premain方法。

Java Agent的使用场景

  • 代码注入增强:允许在程序运行时对字节码进行操作,可以实现功能的增强。
  • 性能监控调优:可以监控应用程序方法执行时间、调用次数,类加载的一些信息进行性能检测,以及对一些问题的定位分析,比如一些性能监控和诊断工具如Pinpoint、Skywalking、Zipkin、Arthas等。
  • 日志记录审计:Java Agent可以在方法执行前后记录方法的调用信息,包括方法名、参数、返回值等,动态记录应用程序的运行日志。

Java Agent的简单使用

1.基于 Instrumentation 接口和premain()方法实现

新建一个maven项目,添加maven-jar-plugin插件依赖,用于打包并生成MANIFREST.MF文件。

java"><build><finalName>agenttestone</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.2.0</version><configuration><archive><!--自动添加META-INF/MANIFEST.MF --><manifest><addClasspath>true</addClasspath></manifest><manifestEntries><!--permain方法所在类的完全限定名--><Premain-Class>com.yifanghub.agent.PremainTest</Premain-Class><Agent-Class>com.yifanghub.agent.PremainTest</Agent-Class><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes></manifestEntries></archive></configuration></plugin></plugins></build>

其中manifestEntries配置了一些属性
<Premain-Class>包含premain方法的类(类的全路径名)
<Agent-Class>包含agentmain方法的类(类的全路径名)
<Can-Redefine-Classes>是否可以重定义此代理所需的类,默认为false
<Can-Retransform-Classes>是否可以重新转换此代理类所需的类,默认为false

新建premain方法测试类,其中premain方法,agentArgs可以通过命令行传入

java">package com.yifanghub.agent;
import java.lang.instrument.Instrumentation;public class PremainTest {public static void premain(String agentArgs, Instrumentation inst) {System.out.println("premain执行---->");System.out.println("Hello agent test,agentArgs="+agentArgs);}
}

新建main方法测试类(新建一个项目)

java">package com.yifanghub.agent;public class PremainAgent {public static void main(String[] args) {System.out.println("agent测试走起,main方法执行");}
}

执行main方法,打印如下:

java">agent测试走起,main方法执行

idea配置:编辑启动类->Add VMOptions

java">-javaagent:D:\javaagent-demo\javaagent-demo-1.0-SNAPSHOT.jar=123运行程序,打印如下:
premain执行---->
Hello agent test,agentArgs=123
agent测试走起,main方法执行

注意事项

  1. agent的方法名必须是premain,否则会报错。

  2. agent抛出异常,会导致主程序的启动失败。

  3. premain方法只允许以下两种定义方式

     1)public static void premain(String agentArgs, Instrumentation inst)2)public static void premain(String agentArgs)JVM 会优先加载带有Instrumentation参数的方法1,加载成功忽略 2,如果1 没有,加载 2 方法。
    

2.基于 Attach 接口和agentmain()方法实现

JDK 1.6后引入了agentmain模式,同样提供了一个agentmain方法,可以在main方法执行之后运行

java">public static void agentmain (String agentArgs, Instrumentation inst)
public static void agentmain (String agentArgs)

1)创建agentmian方法类

java">import java.lang.instrument.Instrumentation;public class AgentmainTest {public static void agentmain(String agentArgs, Instrumentation inst) {System.out.println("agentmain执行---->");System.out.println("Hello I am agentmain test,agentArgs="+agentArgs);}
}

将上面代码打包,名字为:javaagent-demo2-1.0-SNAPSHOT.jar

2)创建被注入的main方法测试类(新建一个项目),这里主要使用一个for循环打印,让程序处于一直运行状态

java">public class MainTest {public static void main(String[] args) {System.out.println("开始执行mian");for (int i = 1; i <= 100000; i++) {System.out.println("第 " + i+ " 次循环");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}
}

3)创建attach项目,编写main方法
这里用到了com.sun.tools.attach 包下面的VirtualMachine工具类来实现,该类表示一个Java虚拟机对象,该类的一些接口如下:

  • list():获取当前所有JVM列表
  • attach():根据进程id,连接到jvm上
  • detach():断开连接
  • loadAgent():加载agent

如果idea里面不能导入VirtualMachine类,导入JDK里面lib下的tool.jar包即可
在这里插入图片描述
attach方法如下:

java">import com.sun.tools.attach.*;
import java.io.IOException;
import java.util.List;public class AgentDemo4Test {public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {System.out.println("AgentDemo4Test");List<VirtualMachineDescriptor> list = VirtualMachine.list();for (VirtualMachineDescriptor vmd : list) {if(vmd.displayName().equals("agent.MainTest")){System.out.println(vmd.displayName());VirtualMachine vm = VirtualMachine.attach(vmd.id());vm.loadAgent("D:\\javaagent-demo2-1.0-SNAPSHOT.jar","123456");vm.detach();}}}
}

4)启动运行MainTest类(第2步打印for循环的程序),然后执行上面AgentDemo4Test类的main方法,输出如下:
在这里插入图片描述
可以看到,我们的agentmain方法的代理已经生效,其中attach方法可以连接到一个正在运行的Java进程当中,之后便可以通过loadAgent方法将我们的jar包注入到对应的进程当中,然后被注入的进程就好调用jar包里的agentmain方法。

注意事项

  • agentmain()​方法会在加载之时立即执行,如果agentmain执行失败或抛出异常,JVM 会忽略掉错误,不会影响到正在运行的程序。

参考:https://www.cnblogs.com/LittleHann/p/17462796.html


http://www.ppmy.cn/news/1424804.html

相关文章

android 修改kernel编译版本信息

1&#xff0c;android版本&#xff1a; 在android/build/core/version_defaults.mk中红色部分 ifeq "" "$(BUILD_NUMBER)" # BUILD_NUMBER should be set to the source control value that # represents the current state of the source code. E.g…

【数学建模】最优旅游城市的选择问题:层次分析模型(含MATLAB代码)

层次分析法&#xff08;The analytic hierarachy process&#xff0c;简称AHP&#xff09;是一种常用的决策分析方法&#xff0c;其基本思路是将复杂问题分解为多个组成部分&#xff0c;然后对这些部分进行逐一评估和比较&#xff0c;最后得出最优解决方案。&#xff08;例如&a…

Git常见命令行操作和IDEA图形化界面操作

设置Git用户名和标签 在安装完Git以后需要设置用户和签名&#xff0c;至于为什么要设置用户签名可以看一下这篇文章【学了就忘】Git基础 — 11.配置Git用户签名说明 - 简书 (jianshu.com) 基本语法&#xff1a; git config --global user.name 用户名 git config --global u…

flutter书架形式格口的动态创建(行、列数,是否全选的配置)

根据传入的行列数创建不同格口数量的书架 左图&#xff1a;5行3列、右图&#xff1a;3行3列 代码 import package:jade/bean/experienceStation/ExpCellSpecsBean.dart; import package:jade/configs/PathConfig.dart; import package:jade/utils/DialogUtils.dart; import p…

【开源】使用Python+Flask+Mysql快速开发一个用户增删改查系统

项目演示 项目本身很简单&#xff0c;增删改查是几乎所有系统的骨架。正所谓万丈高楼平地起&#xff0c;学会了增删改查&#xff0c;航母就指日可待了&#xff1a;&#xff09;&#xff0c;光速入门&#xff0c;直接看演示图&#xff1a; 项目地址 https://github.com/mudf…

鸿蒙画布组件使用介绍

一、前言 DevEco Studio版本&#xff1a;4.0.0.600 前些天写了一篇 鸿蒙自定义控件实现罗盘数字时钟效果 的文章&#xff0c;有同学私信说能不能介绍鸿蒙中的画布组件&#xff0c;下面文章介绍下鸿蒙中的Canvas画布、CanvasRenderingContext2D绘制组件&#xff0c;实现绘制文…

k8s的网络组件有哪些,他们的作用分别是什么

一、以下是k8s的一些网络组件 1. Pod网络 Pod是Kubernetes的基本工作单元&#xff0c;通常包含一个或多个容器。Pod网络负责在Pod之间提供通信能力。Kubernetes支持多种网络解决方案&#xff0c;如&#xff1a; Calico&#xff1a;一个基于BGP的网络解决方案&#xff0c;提供…

7、docker 集群

docker集群 1、docker file参数设置 2、docker composeCompose和Docker兼容性常用参数Docker-compose.yml配置文件Docker-compose命令大全compose常用调试命令compose文件格式示例应用python flask-rediscpu和gpu配置 附件参考&#xff1a; 1、docker file 参考&#xff1a;ht…