使用 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…

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

原定于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 IO演进之路

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

教程系列——用模板快速上线一个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、必…

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

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

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

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

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

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

python关键字中文意思_python 字符串只保留汉字的方法

如下所示&#xff1a; def is_chinese(uchar): """判断一个unicode是否是汉字""" if uchar > u\u4e00 and uchar < u\u9fa5: return True else: return False def is_number(uchar): """判断一个unicode是否是数字"&q…

启明星辰集团DT总部落地杭州 数据绿洲版图驱动未来发展

12月1日&#xff0c;启明星辰集团DT&#xff08;数据时代&#xff09;总部正式落地于杭州高新区&#xff08;滨江&#xff09;&#xff0c;与北京IT总部形成南北两个总部基地新格局&#xff0c;并发布数据安全新版图--数据绿洲&#xff0c;将结合杭州领先的数字应用的场景&…

Quick BI的可视分析之路

简介&#xff1a; Quick BI是专为云上用户量身打造的智能数据分析和可视化BI产品&#xff0c;帮助企业快速完成从传统的数据分析到数据云化分析云化的转变&#xff0c;将企业的业务数据产出后以最快的速度被推送到各组织侧消费使用。本篇着重介绍Quick BI在可视化分析上的能力与…

火山引擎进军云市场,计划未来三年服务十万客户

12月2日&#xff0c;火山引擎在升级为字节跳动企业级技术服务业务板块之后&#xff0c;首次亮相就正式发布全系云产品&#xff0c;包括云基础、视频及内容分发、数据中台、开发中台、人工智能等五大类、共计78项服务。 火山引擎云产品是字节跳动“敏捷开发”技术实践的对外输出…

win7计算机右键属性桌面进程重启,win7计算机右键属性打不开怎么办

有用户在鼠标右击win7桌面计算机选择属性的时候却发现打不开属性窗口&#xff0c;出现这样的情况可能是只要修复一下注册表就可以解决了&#xff0c;那么要如何操作呢?下面是学习啦小编给大家整理的一些有关win7计算机右键属性打不开的解决方法&#xff0c;希望对大家有帮助!w…

看Quick Audience 如何有效提升营销活动管理效率

简介&#xff1a; 营销活动为Quick Audience&#xff08;QA&#xff09;用户洞察下的一个功能模块&#xff0c;通过这个模块&#xff0c;可以将QA侧生成的受众以及营销渠道全部关联起来&#xff0c;从营销活动的视角&#xff0c;一站式完成活动目标制定、活动计划制定到活动任务…

【产品动态】一文详细解读智能数据构建产品Dataphin的“规划”功能

简介&#xff1a; 数据中台是传统的数据仓库的一种升级, 是数据采集、建设、管理与使用的一整套体系&#xff0c;Dataphin是一个构建数据中台的强大工具, 核心优势是在数据的建设与管理上引入了阿里巴巴多年来数据中台建设沉淀出的OneModel方法论。 前言 数据中台是当下大数据…

库克“一语成谶”:又有 30 万台安卓设备被“感染”了!| 文末福利

整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;各家应用商店中的恶意软件总是层出不穷&#xff0c;哪怕是一向以“安全”著称的苹果&#xff0c;也不能完全杜绝 App Store 中恶意软件的乱入。但在这之中&#xff0c;作为“围墙花园”的苹果自认还是高…

深入解读 Flink SQL 1.13

简介&#xff1a; Apache Flink 社区 5 月 22 日北京站 Meetup 分享内容整理&#xff0c;深入解读 Flink SQL 1.13 中 5 个 FLIP 的实用更新和重要改进。 本文由社区志愿者陈政羽整理&#xff0c;Apache Flink 社区在 5 月份发布了 1.13 版本&#xff0c;带来了很多新的变化。文…