java 探针两种模式实战
分为两种
程序运行前的agent:premain
程序运行中的agent:agentmain
在程序运行前的agent
javaagent是java命令的一个参数,所以需要通过-javaagent 来指定一个jar包(就是我们要做的代理包)能够实现在主程序运行前来执行我们jar中的方法
1.pom文件中
<plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version><!-- 指定maven编译的jdk版本。若不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 --><configuration><source>8</source><target>8</target></configuration></plugin><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><Menifest-Version>1.0</Menifest-Version><!-- <Agent-class>example.AgentMain</Agent-class> --><!-- 必须存在 --><Premain-Class>example.PreMainAgent</Premain-Class><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes><!-- <Manifest-Version>true</Manifest-Version>--><!-- <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>--></manifestEntries></archive></configuration></plugin>
</plugins>
也可以使用META-INF/MANIFEST.MF文件
Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.example.PreMainAgent
注意:
- 最后需要多一行空行
- Can-Redefine-Classes :true表示能重定义此代理所需的类, 默认值为 false(可选)
- Can-Retransform-Classes :true 表示能重转换此代理所需的 类,默认值为 false (可选)
- Premain-Class :包含 premain 方法的类(类的全路径名)
程序运行前的agent:PreMainAgent 类
方法名称必须为premain
加载顺序为
premain(String agentArgs,Instrumentation inst)
若找不到则执行
premain(String agentArgs)
public class PreMainAgent {public static void premain(String agentArgs,Instrumentation inst) {System.out.println("agent参数:"+agentArgs);}
}
将此服务打成jar包
创建另一个简单的maven项目
public class Application {public static void main(String[] args) {System.out.println("main 运行 ");}
}
启动运行时增加
-javaagent:D:\agent-demo-1.0-SNAPSHOT.jar=option1=value1
运行结果
agent参数:k1=v1
main 运行
在程序运行中的agent:agentmain类
基础的maven项目
public class AgentMain {public static void agentmain(String agentArgs, Instrumentation inst) {inst.addTransformer(new DefineTransformer(),true);System.out.println("----------我是agentmain");System.out.println("----------agentArgs = " + agentArgs);}
}
addTransformer、getAllLoadedClasses,retransformClasses 方法
addTransformer
用于注册Transformer 可以通过编写ClassFileTransformer 接口的实现类来注册我们自己的转换器
类加载的时候会进入我们自己的Transformer中的transformer 函数进行拦截,此处如果不需拦截也可以不处理
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Scanner;public class DefineTransformer implements ClassFileTransformer {public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {Scanner sc = new Scanner(System.in);System.out.println("Injected Class AgentMainDemo Successfully !");System.out.print("> ");try {InputStream is = Runtime.getRuntime().exec(sc.next()).getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));String line;StringBuilder sb = new StringBuilder();while ((line = br.readLine()) != null){sb.append(line).append("\n");}System.out.println(sb);} catch (IOException e) {e.printStackTrace();}return classfileBuffer;}
}
getAllLoadedClasses
用于列出所有已加载的class ,可以通过遍历class数组来寻找我们需要重新定义的class
public static void agentmain(String agentArgs, Instrumentation inst) {inst.addTransformer(new DefineTransformer(),true);System.out.println("----------监控探针");Class[] allClass = inst.getAllLoadedClasses();for (Class c : allClass) {System.out.println(c.getName());}
}
retransformClasses
能对已加载的class进行重新定义,如果目标类已经被加载了,可以调用此函数重新触发这个拦截能够达到对已加载的类进行字节码修改的效果。
public static final String ClassName = "org.apache.catalina.core.ApplicationFilterChain";public static void agentmain(String agentArgs, Instrumentation inst) {inst.addTransformer(new DefineTransformer(), true);System.out.println("----------监控探针");Class[] allClass = inst.getAllLoadedClasses();for (Class c : allClass) {if (c.getName().equals(ClassName)) {try {System.out.println("Inject class exit :" + ClassName);//agentmain 是JVM运行时,需要调用 retransformClasses 重定义类 !!inst.retransformClasses(c);} catch (UnmodifiableClassException e) {throw new RuntimeException(e);}}}
}
在pom文件里添加
<plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version><!-- 指定maven编译的jdk版本。若不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 --><configuration><source>8</source><target>8</target></configuration></plugin><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><Menifest-Version>1.0</Menifest-Version><Agent-class>example.AgentMain</Agent-class><!-- <Premain-Class>example.PreMainAgent</Premain-Class>--><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes><!-- <Manifest-Version>true</Manifest-Version>--><!-- <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>--></manifestEntries></archive></configuration></plugin>
</plugins>
打成jar包备用
在另一个项目中添加
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;import java.util.List;public class AttachMain {public static void main(String[] args) throws Exception{// 生成jar包的绝对路径String path = "E:\\test-1.0-SNAPSHOT.jar";// 列出已加载的jvmList<VirtualMachineDescriptor> list = VirtualMachine.list();// 遍历已加载的jvmfor (VirtualMachineDescriptor v:list){// 打印jvm的 displayName 属性System.out.println(v.displayName());// 如果 displayName 为指定的类if (v.displayName().contains("AttachMain")){// 打印pidSystem.out.println("id >>> " + v.id());// 将 jvm 虚拟机的 pid 号传入 attach 来进行远程连接VirtualMachine vm = VirtualMachine.attach(v.id());// 将我们的 agent.jar 发送给虚拟机vm.loadAgent(path);// 解除链接vm.detach();}}}
}
注意,此处tools不会自动加载,需要pom文件里手动加载
<dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.8</version><scope>system</scope><systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
运行即可看到
说明已经成功
此时可以启动你的服务,然后修改displayname的判断条件,即可对系统服务是否运行进行监控
后面的服务相当于把上面的jar包挂载到你需要的服务上,可以触发jar包中的代码
相关文章:
java 探针两种模式实战
分为两种 程序运行前的agent:premain 程序运行中的agent:agentmain 在程序运行前的agent javaagent是java命令的一个参数,所以需要通过-javaagent 来指定一个jar包(就是我们要做的代理包)能够实现在主程序运行前来执行…...

uniGUI之MASK遮罩
在页面进行后台数据库操作的时候,不想 用户再进行 页面上的 其他操作,这时候就要 将页面 遮罩。例如UniDBGrid有LoadMask属性。 1]使用ScreenMask函数 2]JS调用 3]一个控件控制遮罩另一个控件(如Button遮罩UniDBGrid) //很简单,本例子就是告…...

DevOps云原生创建devops流水线(微服务项目上传git,打包镜像,部署k8s)
开发和运维人员的解决方案 一、中间件的部署(Sentinel/MongoDB/MySQL) 二、创建DevOps工程 邀请成员 三、创建流水线 四、编辑流水线 ①、拉取代码(若失败,则将制定容器改为maven) 若失败,则将命令改…...
【vim 学习系列文章 13.1 -- 自动命令autocmd 根据文件类型设置vim参数】
文章目录 autocmd 根据文件类型配置vim参数vim 文本类型 autocmd 根据文件类型配置vim参数 在 Vim 中,你可以使用 autocmd (自动命令)来根据文件类型自动执行特定的函数。首先,你需要定义这些函数,然后使用 autocmd 与…...

算法基础概念之数据结构
邻接表 每个点作为头节点接一条链表 链表中元素均为该头节点指向的点 优先队列 参数: ①储存元素类型 ②底层使用的存储结构(一般为vector) ③比较方式(默认小于)...

解决ES伪慢查询
一、问题现象 服务现象 服务接口的TP99性能降低 ES现象 YGC:耗时极其不正常, 峰值200次,耗时7sFULL GC:不正常,次数为1但是频繁,STW 5s慢查询:存在慢查询5 二 解决过程 1、去除干扰因素 从现象上看应用是由于某种…...

关于Ubuntu22.04恢复误删文件的记录
挂载在Ubuntu22.04下的固态盘有文件被误删了,该固态盘是ntfs格式的。 在网上找了很多教程,最后决定用TestDisk工具进行恢复。 现记录如下: Ubuntu安装testdisk sudo apt-get install testdisk运行testdisk sudo testdisk得到 我选择的是…...
Docker笔记:Docker Swarm, Consul, Gateway, Microservices 集群部署
关于 Consul 服务 Consul是Go语言写的开源的服务发现软件Consul具有服务发现、健康检查、 服务治理、微服务熔断处理等功能 Consul 部署方式1: 直接在linux 上面部署 consul 集群 1 )下载 在各个服务器上 下载 consul 后解压并将其目录配置到环境变量中ÿ…...

浅析AI视频分析与视频管理系统EasyCVR平台及场景应用
人工智能的战略重要性导致对视频智能分析的需求不断增加。鉴于人工智能视觉技术的巨大潜力,人们的注意力正在从传统的视频监控转移到计算机视觉的监控过程自动化。 1、什么是视频分析? 视频分析或视频识别技术,是指从视频片段中提取有用信息…...
跨站点分布式多活存储建设方案概述
1-伴随着私有云、海量非结构数据的爆炸性增长,软件定义存储已经成为用户构建“敏捷IT” 架构的数据基石,同时越来越多的关键业务接入“敏捷IT” 架构。在分布式软件定义存储的产品架构下,怎样既保证对爆炸数据量的平稳承接,又能对…...

Github 2023-12-16开源项目日报Top10
根据Github Trendings的统计,今日(2023-12-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目2非开发语言项目2TypeScript项目1Jupyter Notebook项目1Go项目1PHP项目1JavaScript项目1C#项目1 精…...

c++ 中多线程的相关概念与多线程类的使用
1、多线程相关概念 1.1 并发、并行、串行 并发(Concurrent):并发是指两个或多个事件在同一时间间隔内运行。在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机…...

深入理解 hash 和 history:网页导航的基础(下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...

腾讯文档助力CRM集成:无代码连接电商与广告
腾讯文档API的简介与优势 腾讯文档API是一个强大的工具,它允许企业通过简单的无代码开发来实现与电商平台和客服系统的智能连接。这种连接不仅提高了工作效率,还优化了数据管理。使用腾讯文档智能表,商家可以享受多样的列类型、多维视图展示…...

学习使用echarts漏斗图的参数配置和应用场景
学习使用echarts漏斗图的参数配置和应用场景 前言什么是漏斗图漏斗图的特点及应用场景漏斗图的特点漏斗图常见的的应用场景: echarts中漏斗的常用属性echart漏斗代码美化漏斗图样式1、设置标题字体大小2、设置标签样式3、设置漏斗图为渐变颜色4、设置高亮效果5、设置…...

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源
在平时开发当中,我们经常会使用 Npm,yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的,如果没有梯子的话。会感觉特别特别慢,所以,使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm, yarn …...
vue+react题集整理
1.Typescript中 interface 和 type 的差别是什么? interface只能用来描述对象类型 type可以描述任何类型组合 type后边需要有 interface后边没有 当多次使用相同名称定义一个 interface 时,它们会自动合并为一个接口。同名属性的不能进行类型覆盖修改&am…...
线程池ThreadPoolExecutor详解
线程池ThreadPoolExecutor详解 大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天,让我们深入研究Java中线程池的强大工具——ThreadPoolExecutor,解析它的工作原理、配置参数…...

elasticsearch|大数据|kibana的安装(https+密码)
前言: kibana是比较好安装的,但https密码就比较麻烦一些了,下面将就如何安装一个可在生产使用的kibana做一个简单的讲述 一, kibana版本和下载地址 这里我想还是强调一下,kibana的版本需要和elasticsearch的版本一…...

vue javascript tree 层级数据处理
层级数据是有父子关系的数组,示例: const treeData [{id: 1b7e8e98cb1d4a1f81e4fe2dfd9a8458,name: 层级1,parentId: null,children: [{id: 0d45dd5bb4c14d64a3ab0b738add4b24,name: 层级1-1,parentId: 1b7e8e98cb1d4a1f81e4fe2dfd9a8458,children: [{…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...

FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...