使用 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.tpcf.cn/news/513098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;成为…