使用 Arthas 排查开源 Excel 组件问题

简介: 有了实际的使用之后,不免会想到,Arthas 是如何做到在程序运行时,动态监测我们的代码的呢?带着这样的问题,我们一起来看下 Java Agent 技术实现原理。

背景介绍

项目中有使用到 com.github.dreamroute excel-helper 这个工具来辅助 Excel 文件的解析,出错时的代码是这样写的:如下所示(非源代码)

     try {            excelDTOS = ExcelHelper.importFromFile(ExcelType.XLSX, file, ExcelDTO.class);        } catch (Exception e) {            log.error("ExcelHelper importFromFile exception msg {}", e.getMessage());        }

因为打印异常信息时,使用了 e.getMessage() 方法,没有将异常信息打印出来。而且本地复现也没有复现出来。所以只能考虑使用 arthas 来协助排查这个问题了。

排查过程

1、线上服务器安装 Arthas。
https://arthas.aliyun.com/doc/install-detail.html

2、使用 watch 命令监控指定方法,打印出异常的堆栈信息,命令如下:

watch com.github.dreamroute.excel.helper.ExcelHelper importFromFile '{params,throwExp}' -e -x 3

再次调用方法,捕获到异常栈信息如下:

已经捕获到异常,并打印出堆栈信息。

3、根据对应的堆栈信息,定位到具体的代码,如下:

代码很简单,从代码中可以很清晰的看到如果没有从 headerInfoMap 中没有获取到指定的 headerInfo ,就会抛这个异常。没有找到只有两种情况:

  • headerInfoMap 中保存的信息不对。
  • cell 中的 columnIndex 超出的正常的范围导致没有获取到对应 HeaderInfo 。

对于第二种情况,首先去校验了一下上传的 Excel 文件是否有问题,本地测试了一下 Excel 文件,没有任何问题。本地测试也是成功的,所以主观判断,第二种情况的可能性不大。

所以说主要检查第一种情况是否发生,这个时候可以再去看一下该方法的第一行代码

MapheaderInfoMap = processHeaderInfo(rows,cls);

可以看到headerInfoMap是通过processHeaderInfo中获取的。找到processHeaderInfo 的代码,如下所示。

public static MapproceeHeaderInfo(Iteratorrows, Class cls) {if (rows.hasNext()) {Row header = rows.next();return CacheFactory.findHeaderInfo(cls, header);}return new HashMap<>(0);
}
public static MapfindHeaderInfo(Class cls, Row header) {MapheaderInfo = HEADER_INFO.get(cls);if (MapUtils.isEmpty(headerInfo)) {headerInfo = ClassAssistant.getHeaderInfo(cls, header);HEADER_INFO.put(cls, headerInfo);}return headerInfo;
}
public static MapgetHeaderInfo(Class cls, Row header) {IteratorcellIterator = header.cellIterator();Listfields = ClassAssistant.getAllFields(cls);MapheaderInfo = new HashMap<>(fields.size());while (cellIterator.hasNext()) {org.apache.poi.ss.usermodel.Cell cell = cellIterator.next();String headerName = cell.getStringCellValue();for (Field field : fields) {Column col = field.getAnnotation(Column.class);String name = col.name();if (Objects.equals(headerName, name)) {HeaderInfo hi = new HeaderInfo(col.cellType(), field);headerInfo.put(cell.getColumnIndex(), hi);break;}}}return headerInfo;
}

主要通过 CacheFactory 类的 findHeaderInfo 来生成,在 findHeaderInfo 方法中,通过一个被 static final 修饰的 HEADER_INFO 变量来做缓存,被调用时先去HEADER_INFO 中查,如果有则直接返回,没有则重新创建(也就说明相同的 Excel 文件,仅初始化一次 HeaderInfo )。创建的步骤在 ClassAssistant.getHeaderInfo() 方法中。

简单的看一下 HeaderInfo 的生成过程,根据 Excel 文件的第一行中的各个 Cell 值与自定义实体类的注解比较,如果名字相同,就存为一个键值对( HeaderInfo 的数据结构为 HashMap )。

4、这个时候需要再确认一下 HEADER_INFO 中保存的 ExcelDTO.class 相关的 HeaderInfo 是怎样的。通过 ognl 命令或者 getstatic 命令来查看。这里使用 ognl 命令。

ognl '#value=new com.tom.dto.ExcelDTO(),#valueMap=@com.github.dreamroute.excel.helper.cache.CacheFactory@HEADER_INFO,#valueMap.get(#value.getClass()).entrySet().iterator.{#this.value.name}'

结果如下:正常情况下这个 Excel 文件有 6 列信息,为什么只产生了 4 个键值对呢?如果 HEADER_INFO 中保存了错的,从上面的逻辑来看,后面上传的正确的 Excel 文件在解析时都会抛错。

5、询问了当时发现这个问题的同事,得知他第一次上传的 Excel 文件是有问题的,后面想改正,再上传时便出现了问题。到这里问题也算是找到了。

Arthas 原理探究

有了实际的使用之后,不免会想到,Arthas 是如何做到在程序运行时,动态监测我们的代码的呢?带着这样的问题,我们一起来看下 Java Agent 技术实现原理。

Java Agent 技术

Agent 是一个运行在目标 JVM 的特定程序,它的职责是负责从目标 JVM 中获取数据,然后将数据传递给外部进程。加载 Agent 的时机可以是目标 JVM 启动之时,也可以是在目标 JVM 运行时进行加载,而在目标 JVM 运行时进行 Agent 加载具备动态性。

基础概念

  • JVMTI(JVM Tool Interface):是 JVM 暴露出来的一些供用户扩展的接口集合,JVMTI 是基于事件驱动的,JVM 每执行到一定的逻辑就会调用一些事件的回调接口(如果有的话),这些接口可以供开发者去扩展自己的逻辑。
  • JVMTIAgent(JVM Tool Interface):是一个动态库,利用 JVMTI 暴露出来的一些接口帮助我们在程序启动时或程序运行时 JVM Attach 机制,将 Agent 加载到目标 JVM 中。
  • JPLISAgent(Java Programming Language Instrumentation Services Agent):它的作用是初始化所有通过 Java Instrumentation API 编写的 Agent,并且也承担着通过 JVMTI 实现 Java Instrumentation 中暴露 API 的责任。
  • VirtualMachine :提供了Attach 动作和 Detach 动作,允许我们通过 attach 方法,远程连接到 JVM 上,然后通过 loadAgent 方法向 JVM 注册一个代理程序 agent ,在该 agent 的代理程序中会得到一个 Instrumentation 实例,该实例可以在 class 加载前改变 class 的字节码,也可以在 class 加载后重新加载。
  • Instrumentation:可以在 class 加载前改变 class 的字节码(premain),也可以在 class 加载后重新加载(agentmain)。

执行过程

动手写一个 Demo

通过 javassist,在运行时更改指定方法的代码,在方法之前后添加自定义逻辑。

1、定义 Agent 类。当前 Java 提供了两种方式可以将代码代码注入到 JVM 中,这里我们的 Demo 选择使用 agentmain 方法来实现。

premain:在启动时通过 javaagent 命令,将代理注入到指定的 JVM 中。
agentmain:运行时通过 attach 工具激活指定代理。

/*** AgentMain** @author tomxin*/
public class AgentMain {public static void agentmain(String agentArgs, Instrumentation instrumentation) throws UnmodifiableClassException, ClassNotFoundException {instrumentation.addTransformer(new InterceptorTransformer(agentArgs), true);Class clazz = Class.forName(agentArgs.split(",")[1]);instrumentation.retransformClasses(clazz);}
}/*** InterceptorTransformer** @author tomxin*/
public class InterceptorTransformer implements ClassFileTransformer {private String agentArgs;public InterceptorTransformer(String agentArgs) {this.agentArgs = agentArgs;}@Overridepublic byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {//javassist的包名是用点分割的,需要转换下if (className != null && className.indexOf("/") != -1) {className = className.replaceAll("/", ".");}try {//通过包名获取类文件CtClass cc = ClassPool.getDefault().get(className);//获得指定方法名的方法CtMethod m = cc.getDeclaredMethod(agentArgs.split(",")[2]);//在方法执行前插入代码m.insertBefore("{ System.out.println(\"=========开始执行=========\"); }");m.insertAfter("{ System.out.println(\"=========结束执行=========\"); }");return cc.toBytecode();} catch (Exception e) {}return null;}
}

2、使用 Maven 配置 MANIFEST.MF 文件,该文件能够指定 Jar 包的 main 方法。

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.3.1</version><configuration><archive><manifest><addClasspath>true</addClasspath></manifest><manifestEntries><Agent-Class>com.tom.mdc.AgentMain</Agent-Class><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes></manifestEntries></archive></configuration></plugin></plugins></build>

3、定义 Attach 方法,通过 VirtualMachine.attach(#{pid}) 来指定要代理的类。

import com.sun.tools.attach.VirtualMachine;import java.io.IOException;/*** AttachMain** @author tomxin*/
public class AttachMain {public static void main(String[] args) {VirtualMachine virtualMachine = null;try {virtualMachine = VirtualMachine.attach(args[0]);// 将打包好的Jar包,添加到指定的JVM进程中。virtualMachine.loadAgent("target/agent-demo-1.0-SNAPSHOT.jar",String.join(",", args));} catch (Exception e) {if (virtualMachine != null) {try {virtualMachine.detach();} catch (IOException ex) {ex.printStackTrace();}}}}
}

4、定义测试的方法
 

package com.tom.mdc;
import java.lang.management.ManagementFactory;
import java.util.Random;
import java.util.concurrent.TimeUnit;/*** PrintParamTarget** @author toxmxin*/
public class PrintParamTarget {public static void main(String[] args) {// 打印当前进程IDSystem.out.println(ManagementFactory.getRuntimeMXBean().getName());Random random = new Random();while (true) {int sleepTime = 5 + random.nextInt(5);running(sleepTime);}}private static void running(int sleepTime) {try {TimeUnit.SECONDS.sleep(sleepTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("running sleep time " + sleepTime);}
}

原文链接
本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/513098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何选择python书籍_关于 Python 的经典入门书籍有哪些?

展开全部 关于Python&#xff0c;是最近最火最的编程语言e68a843231313335323631343130323136353331333365643631&#xff0c;挺多人都在学习的&#xff0c;关于它的入门书籍&#xff0c;我大概推荐以下几本&#xff1a; 首先我介绍的是《Python基础教程(第2版修订版)》&#x…

echarts 折线图 html模板,设置ECharts折线图的提示框

回调函数回调函数格式&#xff1a;(params: Object|Array, ticket: string, callback: (ticket: string, html: string)) > string第一个参数 params 是 formatter 需要的数据集。格式如下&#xff1a;{componentType: series,// 系列类型seriesType: string,// 系列在传入的…

“融合、智能、绿色”施耐德电气线上工博以全生命周期解决方案助推数字化

原定于12月1-5日在上海举办的第23届中国国际工业博览会因为疫情再次延期。不必翘首等待&#xff0c;施耐德电气将以线上云展厅的形式如期与您见面&#xff0c;为工业用户呈现一场以“绿色智能制造&#xff0c;共塑可持续未来”为主题的云端盛宴。凭借在绿色智能制造领域的丰富实…

运维更简单、更智能,让运维人不再 “拼命”

简介&#xff1a; 云原生智能运维解决方案&#xff0c;利用大数据为企业日常运维服务&#xff0c;通过可观测数据&#xff0c;融合智能告警与响应中枢&#xff0c;结合机器学习的方法进一步解决自动化运维所未解决的问题&#xff0c;让运维更简单、更智能。 在90%的科幻片中 万…

python全栈马哥_马哥Python全栈+爬虫+高端自动化,资源教程下载

资源名称 马哥Python全栈爬虫高端自动化&#xff0c;资源教程下载 资源介绍 这套课程最后是有项目实战的&#xff0c;如项目四-多人博客开发、项目五CMDB资产管理、项目七-运维流程系统。 资源目录 01Python开班仪式及职业指导 02linux基础-1 03linux基础-2 04linux基础-3 05li…

java 高并发mqtt服务器_Boomer 实战压测 mqtt,2w 并发轻松实现

// main.go// 代码仅供参考,无法直接运行.package mainimport ("bytes""encoding/csv""fmt"MQTT "github.com/eclipse/paho.mqtt.golang""github.com/myzhan/boomer""io""io/ioutil""log"&qu…

从操作系统层面分析Java IO演进之路

简介&#xff1a; 本文从操作系统实际调用角度&#xff08;以CentOS Linux release 7.5操作系统为示例&#xff09;&#xff0c;力求追根溯源看IO的每一步操作到底发生了什么。 作者 | 道坚 来源 | 阿里技术公众号 前言 本文从操作系统实际调用角度&#xff08;以CentOS Linu…

AI是计算机科学,人工智能计算机科学(79种)...

COMPUTER SCIENCE, ARTIFICIAL INTELLIGENCE(人工智能计算机科学) 79种1. ADVANCED ENGINEERING INFORMATICSQuarterlyISSN: 1474-0346ELSEVIER SCI LTD, THE BOULEVARD, LANGFORD LANE, KIDLINGTON, OXFORD, ENGLAND, OXON, OX5 1GB2. AI COMMUNICATIONSQuarterlyISSN: 0921-7…

教程系列——用模板快速上线一个HR 服务中心

简介&#xff1a; 【开箱即用的模板使用系列教程】将会手把手教给大家如何快速启用钉钉宜搭提供各类模板。今天第一讲&#xff0c;介绍《HR 服务中心》的模板启用。 【开箱即用的模板使用系列教程】将会手把手教给大家如何快速启用钉钉宜搭提供各类模板。今天第1讲&#xff0c;…

数字化“团险”黑科技,保险极客技术升级背后心经

作者 | 宋慧 出品 | CSDN 云计算 疫情之后&#xff0c;一切都在“内卷”&#xff0c;HR 也逃不过。初创公司想要招到优秀人才&#xff0c;除了对市场和未来发展的预期和潜力&#xff0c;提供补充医疗险也是对人才重要的保障。另外&#xff0c;现在补充医疗也是知名大企业高福利…

powershell快捷键_借助Windows Terminal搞一个花里胡哨的PowerShell终端

一提起PowerShell&#xff0c;命令提示符等等&#xff0c;想到的就是丑、难用&#xff0c;非常丑&#xff01;各位可以先感受一下。不过&#xff0c;现在我们可以对它做一个美化&#xff0c;美化后的效果如下&#xff0c;各位也可以感受下(本人不提供背景图)下面做简单记录1、必…

linux刷新本地dns命令_两种方法修改Linux下的DNS后立即生效 - 文中之舞

DNS服务器介绍DNS是计算机域名系统(Domain Name System 或Domain Name Service) 的缩写&#xff0c;它是由域名解析器和域名服务器组成的。域名服务器是指保存有该网络中所有主机的域名和对应IP地址&#xff0c;并具有将域名转换为IP地址功能的服务器。其中域名必须对应一个IP地…

【详谈 Delta Lake 】系列技术专题 之 特性(Features)

简介&#xff1a; 本文翻译自大数据技术公司 Databricks 针对数据湖 Delta Lake 的系列技术文章。众所周知&#xff0c;Databricks 主导着开源大数据社区 Apache Spark、Delta Lake 以及 ML Flow 等众多热门技术&#xff0c;而 Delta Lake 作为数据湖核心存储引擎方案给企业带来…

*计算机应用基础* 说课稿,中职计算机应用基础《EXCEL中函数的使用》说课稿.doc...

中职计算机应用基础《EXCEL中函数的使用》说课稿说课稿《EXCEL中函数的使用》选用教材&#xff1a;《计算机应用基础》高等教育出版社出版各位专家、评委好&#xff01;我说课的题目是《EXCEL中函数的使用》&#xff0c;下面我将从教材、教法、学法以及教学程序设计等方面加以说…

python cmp函数未定义_python用plt画图时,cmp设置方法

在python&#xff0c;有时候是需要画图的&#xff0c;比如把一个矩阵用图像的形式显示&#xff0c;之前用的好好的&#xff0c;每次用plt.imshow()&#xff0c;都是彩色图&#xff0c;不知为啥&#xff0c;突然全是黑白图了&#xff0c;于是需要设置cmap的值&#xff0c;如下&a…

sid图像数据_MrSID技术在GIS中的应用

摘要&#xff1a;随着卫星遥感和航空摄影技术的发展&#xff0c;通过遥感获得的地理信息越来越多&#xff0c;特别是小卫星高分辨率遥感图象的商业化(如EOSAT)&#xff0c;遥感影像成为地理信息系统(GIS)一个非常重要的信息源&#xff0c;这对海量数据的及时存储与传输提出了很…

聚焦四大领域,恒生电子发布2022年金融科技技术与应用趋势

12月1日&#xff0c;恒生电子在2021 LIGHT开发者云大会上正式发布《2022金融科技趋势研究报告》&#xff08;以下简称“报告”&#xff09;。报告详细分析2022年金融科技在数据、智能、效率、安全四大领域的核心技术与应用发展趋势&#xff0c;并对VR、量子计算等前沿技术对金融…

深度解读畅捷通云原生架构转型实战历程

简介&#xff1a; 畅捷通公司是用友集团旗下的成员企业&#xff0c;专注于服务国内小微企业的财务和管理服务。一方面&#xff0c;畅捷通将自己的产品、业务、技术架构互联网化&#xff1b;另一方面&#xff0c;畅捷通推出了畅捷通一站式云服务平台&#xff0c;面向小微企业提供…

万兴剪刀手去水印教程_万兴神剪手怎么去水印 去除logo水印方法

万兴神剪手默认情况下得到的视频是带有水印的呢&#xff0c;相信很多人都想要知道去除掉这个水印吧&#xff0c;要是不知道怎么操作的话可以看看下面的教程。类别&#xff1a;视频处理 大小&#xff1a;188.74M 语言&#xff1a;简体中文评分&#xff1a;61、首先点击其中…

Apache Dubbo 3.0.0 正式发布 - 全面拥抱云原生

简介&#xff1a; 一个新的里程碑&#xff01; 一、背景 自从 Apache Dubbo 在 2011 年开源以来&#xff0c;在一众大规模互联网、IT公司的实践中积累了大量经验后&#xff0c;Dubbo 凭借对 Java 用户友好、功能丰富、治理能力强等优点在过去取得了很大的成功&#xff0c;成为…