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: [{…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...