成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用 Arthas 排查開源 Excel 組件問題

開發
JVMTI(JVM Tool Interface):是 JVM 暴露出來的一些供用戶擴展的接口集合,JVMTI 是基于事件驅動的,JVM 每執行到一定的邏輯就會調用一些事件的回調接口(如果有的話),這些接口可以供開發者去擴展自己的邏輯。

 [[408346]]

背景介紹

項目中有使用到 com.github.dreamroute excel-helper 這個工具來輔助 Excel 文件的解析,出錯時的代碼是這樣寫的:如下所示(非源代碼)

  1. 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 文件,沒有任何問題。本地測試也是成功的,所以主觀判斷,第二種情況的可能性不大。

所以說主要檢查第一種情況是否發生,這個時候可以再去看一下該方法的第一行代碼

  1. MapheaderInfoMap = processHeaderInfo(rows,cls); 

可以看到headerInfoMap是通過processHeaderInfo中獲取的。找到processHeaderInfo 的代碼,如下所示。

  1. 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 命令。

  1. 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 工具激活指定代理。

  1. /** * 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; } @Override public 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 方法。

  1. <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}) 來指定要代理的類。

  1. import com.sun.tools.attach.VirtualMachine;import java.io.IOException;/** * AttachMain * * @author tomxin */public class AttachMain { public static void main(String[] args) { VirtualMachine virtualMachine = nulltry { 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、定義測試的方法

  1. 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) { // 打印當前進程ID System.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); }} 

 

責任編輯:梁菲 來源: 阿里云云棲號
相關推薦

2024-04-30 08:09:10

PulsarArthas消息隊列

2021-04-19 17:25:08

Kubernetes組件網絡

2023-03-03 09:33:45

ArthasJava診斷工具

2009-08-21 09:14:47

C# Excel CO

2021-06-01 09:29:43

ArthasJVM內存

2020-10-28 15:07:01

Arthas

2022-05-08 09:11:44

WiFi樹莓派GO

2010-08-04 14:28:01

Flex組件

2024-09-10 09:31:07

開源項目Arthas

2025-05-08 08:20:00

Arthas開源Java

2024-08-14 14:20:00

2020-12-07 11:12:16

MySOLBinlogOtter

2021-11-14 05:00:56

排查Sdk方式

2022-01-26 19:42:05

MySQL亂碼排查

2021-06-01 07:55:42

DockerEOFk8s

2021-12-01 15:03:56

Java開發代碼

2020-04-23 10:07:45

工具IDEA阿里巴巴

2025-03-18 08:10:00

iodump開源I/O

2024-11-22 09:40:18

Visual內存泄漏內存

2024-11-21 09:30:38

內存泄漏CPU
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91免费在线播放 | 久久激情视频 | 国产在线不卡视频 | 国产综合精品 | 日日干干 | 中文字幕免费观看 | 国产a爽一区二区久久久 | 午夜专区 | 在线观看www视频 | 91免费看片| 精品国产欧美一区二区 | 懂色av色香蕉一区二区蜜桃 | 日韩免费av一区二区 | 精品国产欧美日韩不卡在线观看 | 黄毛片| 国产1区2区在线观看 | 综合久久99 | 草草网 | 麻豆久久久久 | 不卡一区二区三区四区 | 午夜专区| 国产精品18久久久久久白浆动漫 | 欧美激情综合 | 男人天堂国产 | 日本精品免费在线观看 | 亚洲综合无码一区二区 | 男女啪啪高潮无遮挡免费动态 | 精品毛片视频 | 一区二区三区在线观看视频 | 成人亚洲精品 | 98成人网 | 伊人中文字幕 | 久久精品一区二区三区四区 | 天天干天天操 | 99视频入口| 在线观看你懂的网站 | 日韩a视频| 亚洲一区高清 | 国产亚洲一区二区三区在线观看 | 精品久久久久久18免费网站 | 国产亚洲一级 |