java agent使用

2024-03-02 10:44
文章标签 java 使用 agent

本文主要是介绍java agent使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是java agent

本质是一个jar包中的类,有两种实现,第一种是通过permain()函数实现。这种javaagent会在宿主程序的main函数的启动前启动自己premain函数,这时候会得到一个Instrumentation对象,我们可以通过Instrumentation对象对还未加载的class进行拦截与修改。

还有一种实现方式是利用agentmain()函数。VirtualMachine类的attach(pid)方法可以将当前进程attach到一个运行中的java进程上,接着利用loadAgent(agentJarPath)来将含符合格式且含有agentmain函数的jar包注入到对应的进程,调用loadAgent函数后,对应的进程中会多出一个Instrumentation对象,这个对象会被当作agentmain的一个参数。对应进程接着会调用agentmain函数,进而操作Instrumentation对象,Instrumentation对象可以在class加载前拦截字节码进行修改,也可以对已经加载的class重新让它加载,并拦截且修改其中的内容,跟进程注入差不多,具体做什么操作,取决于我们的jar文件中的agentmain函数怎么写。

Java agent的使用方式有两种:

实现premain方法,在JVM启动前加载。

实现agentmain方法,在JVM启动后加载。

agent基础使用

环境搭建

agent项目源码

agent:

package com.naihe;import java.io.IOException;
import java.lang.instrument.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.ProtectionDomain;public class agent {//java agent 入口public static void premain(String agentOps, Instrumentation inst) {System.out.println("=========premain方法执行========");simpleDemo(agentOps, inst);}public static void agentmain(String agentOps, Instrumentation inst) {System.out.println("=========agentmain方法执行========");simpleDemo(agentOps, inst);//transform是会对尚未加载的类进行增加代理层,这里是已经运行中的jvm,所以类以及被加载了//必须主动调用retransformClasses让jvm再对运行中的类进行加上代理层for (Class allLoadedClass : inst.getAllLoadedClasses()) {//这里的Test路径,修改成你自己机器agent-demo-web工程的Test类的路径if(allLoadedClass.getName().contains("com.naihe.Demo")){try {inst.retransformClasses(allLoadedClass);} catch (UnmodifiableClassException e) {e.printStackTrace();}}}}public static void simpleDemo(String agentOps, Instrumentation inst) {inst.addTransformer(new ClassFileTransformer() {@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {//判断是指定的classif ("com/naihe/Demo".equals(className)) {try {//获取更改后的类class 字节数组String path="C:/Users/12107/Desktop/Demo2.class";classfileBuffer = Files.readAllBytes(Paths.get(path));} catch (IOException e) {e.printStackTrace();}}return classfileBuffer;}},true);}}

app项目源码

application:

Demo:

attach:

package com.naihe;import com.sun.tools.attach.*;import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;public class attach {public static void main(String[] args) {//查找所有jvm进程,排除attach测试工程List<VirtualMachineDescriptor> attach = VirtualMachine.list().stream().filter(jvm -> {return !jvm.displayName().contains("attach");}).collect(Collectors.toList());for (int i = 0; i < attach.size(); i++) {System.out.println("[" + i + "] " + attach.get(i).displayName()+":"+attach.get(i).id());}System.out.println("请输入需要attach的pid编号");Scanner scanner = new Scanner(System.in);String s = scanner.nextLine();VirtualMachineDescriptor virtualMachineDescriptor = attach.get(new Integer(s));try {VirtualMachine virtualMachine = VirtualMachine.attach(virtualMachineDescriptor.id());virtualMachine.loadAgent("C:\\Users\\12107\\Desktop\\agent.jar", "param");virtualMachine.detach();} catch (AttachNotSupportedException e) {System.out.println("AttachNotSupportedException:" + e.getMessage());} catch (IOException e) {System.out.println("IOException:" + e.getMessage());} catch (AgentLoadException e) {System.out.println("AgentLoadException:" + e.getMessage());} catch (AgentInitializationException e) {System.out.println("AgentInitializationException:" + e.getMessage());}}
}

retransformClasses:对于已经加载的类重新进行转换处理,即会触发重新加载类定义,需要注意的是,新加载的类不能修改旧有的类声明,譬如不能增加属性、不能修改方法声明

静态修改class

一,将agent打包成jar包

进入classes目录

这边直接打包得com文件,因为这只是一个小Demo给大家演示一下,并没有使用字节码相关的库

二,修改MANIFEST.MF

使用解压工具打开MANIFEST.MF,并修改内容

三,加载agent.jar

运行app中的application

使用ideal加载jar

动态修改class

清除之前的内容

正常运行

运行attach

可以看到Demo的test方法已经被修改了

这篇关于java agent使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/765853

相关文章

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca

C#下Newtonsoft.Json的具体使用

《C#下Newtonsoft.Json的具体使用》Newtonsoft.Json是一个非常流行的C#JSON序列化和反序列化库,它可以方便地将C#对象转换为JSON格式,或者将JSON数据解析为C#对... 目录安装 Newtonsoft.json基本用法1. 序列化 C# 对象为 JSON2. 反序列化

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映