首頁 > 軟體

《Arthas系列2》三分鐘理解Java如何使用命令列

2021-05-16 14:00:38

點贊再看,養成讚美的習慣,微信搜一搜【香菜聊遊戲】關注我。

今天學習一下Arthas是如何打印出當前機器上的所有Java執行緒的和呼叫控制檯的,這個技術點不清楚,我們從Arthas的程式碼中找出實現,學習下知識點,在下次自己用的時候可以有思路,但是Arthas的程式碼量如此之多,在沒人帶的情況下怎麼讀程式碼吶?

1、如何根據表現查程式碼

1.1 偵錯斷點,因為上篇文章我已經介紹了怎麼偵錯,能偵錯的程式碼一定要偵錯,斷電跟蹤程式碼,因此我也想偵錯的方式去跟蹤程式碼,但是我在打上斷點的時候,並且使用命令之後,啟動之後發現斷點沒有生效,思考下為什麼沒有生效?上期的文章有答案,偵錯程式的原理。

java -jar arthas-boot.jar

1.2 讀程式碼,既然要讀程式碼了就不能怕讀程式碼,讀程式碼不需要任何的環境,不要任何的測試,不需要任何的條件,只要跟著程式碼的走向即可。帶好小本,記錄好自己的理解。

1.3 舉例

看到列印的日誌如下,既然想看他的源碼, 從運行的日誌列印,分析日誌的內容,發現列印的也沒有參數,直接拷貝。不要想那麼多,直接全局搜尋,找到下面的不少用處,我們稍微掃一下就看到了很多地方不是程式碼呼叫,我們直接定位到Arthas-boot,OK,我們找到了這個程式碼的源頭,直接進入理解階段。

2、如何實現自己的java 程序列表

在跟蹤程式碼程式碼的過程中,也要理清楚思路,作者到底是怎麼做成這件事,如果是你 會有什麼樣的思路,如果你的思路剛好和作者的不謀而合,我相信你理解起來程式碼就很簡單,如果你的思路和作者的不同,我們應該思考為什麼Arthas的作者這麼做,你的方案是不是更好,盡信書不如無書!我們帶著問題開始吧。

1、訪問環境變數,如何找到jps

1.1 如何讀取電腦的環境變數 :System.getProperty("java.home")

1.2 jps 是什麼?jps是java提供的一個顯示當前所有java程序pid的命令,我們發現了事情的核心。

1.3 如何找到jps ?jps 的路徑可能不同,或者Arthas運行的系統不同,作者直接列出了所有的可能路徑,總有一個蒙準。

privatestaticFilefindJps() {// Try to find jps under java.home and System env JAVA_HOMEStringjavaHome=System.getProperty("java.home");String[] paths= { "bin/jps", "bin/jps.exe", "../bin/jps", "../bin/jps.exe" };List<File>jpsList=newArrayList<File>();for (Stringpath : paths) {FilejpsFile=newFile(javaHome, path);if (jpsFile.exists()) {AnsiLog.debug("Found jps: "+jpsFile.getAbsolutePath());jpsList.add(jpsFile);} }//省略了不重要的程式碼 }

2、jps命令格式

問題:jps 命令 的執行格式

看程式碼中jps 有兩種方式,一種加V ,資訊更多,一種不加v 僅僅列出了所有的執行緒。

String[] command = null; if (v) { command = new String[] { jps, "-v", "-l" }; } else { command = new String[] { jps, "-l" }; } List<String> lines = ExecutingCommand.runNative(command);

3、運行cmd

我們看到Arthas是在控制檯視窗中運行的,我們的問題是:

3.1 怎麼執行命令?使用runtime的exec介面,直接呼叫系統命令

3.2 Process 是什麼?process是代表一個程序,啟動的控制檯視窗就是一個Process

publicstaticList<String>runNative(String[] cmdToRunWithArgs) {Processp=null;try {p=Runtime.getRuntime().exec(cmdToRunWithArgs);

4、讀取輸出並編號

程式碼所在位置:com.taobao.arthas.common.ExecutingCommand#runNative(java.lang.String[])

問題:怎麼讀取控制檯視窗的輸出,或者說接管控制檯視窗,使用process.getInputStream() 獲取控制檯的輸出。

ArrayList<String> sa = new ArrayList<String>(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); try { String line; while ((line = reader.readLine()) != null) { sa.add(line); }

3、一步步實現程式碼

核心技術點是呼叫jps.exe 的命令如何執行命令 jps -l輸出控制檯輸出完整程式碼:packagecom.taobao.arthas.core;importjava.io.BufferedReader;importjava.io.File;importjava.io.IOException;importjava.io.InputStreamReader;/*** 獲得機器上所有Java執行緒

* @author 香菜*/publicclassAain {publicstaticvoidmain(String[] args) throwsIOException {//1、獲取jps地址,執行完成之後可以看下對應的路徑下是否有jps.exeStringjpsPath=getJpsPath();//2、運行cmdrunCmd(jpsPath);}/*** 讀取輸出* @param reader* @throws IOException*/privatestaticvoidreadOutput(BufferedReaderreader) throwsIOException {try {Stringline;while ((line=reader.readLine()) !=null) {System.out.println(line); } } catch (Exceptione) {e.printStackTrace(); } finally {reader.close(); } }/*** 運行cmd* @param jpsPath* @throws IOException*/privatestaticvoidrunCmd(StringjpsPath) throwsIOException {String[] cmdStr=newString[] { jpsPath, "-l" };Processp=null;try {p=Runtime.getRuntime().exec(cmdStr); } catch (Exceptione) {return; }readOutput(newBufferedReader(newInputStreamReader(p.getInputStream()))); }/*** 獲得jps.exe 的地址* @return*/privatestaticStringgetJpsPath() {StringjavaHome=System.getProperty("java.home");// 因為在windows環境下演示,只處理window 環境returnnewFile(javaHome, "../bin/jps.exe").getAbsolutePath(); }}

運行結果:

4、總結:

每個問題的解決,最初的樣子都很簡單,只是因為加了異常處理,或者特殊需求,或者更全面才成為最終的樣子,我們要從複雜的程式碼中看到技術的本質問題,而不是在大量的程式碼中迷失。

今天主要學會了怎麼呼叫控制檯,讀取控制檯輸出,以及jps的使用,你都明白了嗎?


IT145.com E-mail:sddin#qq.com