日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java动态追踪技术--BTrace

發布時間:2023/12/4 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java动态追踪技术--BTrace 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java動態追蹤技術

  • 需求翻譯官的日常工作不是在的改bug,發布代碼,就是在加日志查找bug的路上。查BUG的過程是痛苦的,我們總是在不停的看代碼,修改代碼,添加日志,從而幫助我們發現問題,這種形式是比較繁瑣的,不斷的在發布項目,開發效率也不高,而且線上的問題排查不可能讓你經常添加調試代碼,能不能找到一種和JSP一樣快捷的方式呢。
JSP模式
  • 對應大多數程序員來說,早期的時候都接觸過JSP(java server pages)。雖然之后在前后端分離的主流思想下主鍵淘汰不用了,但是JSP還是有一些比較值得我們去思考的點,例如我們在使用JSP寫頁面效果的時候,修改代碼只需要刷新頁面,而不需重啟服務,就可以看到頁面展示效果。并不需要重啟JVM。

  • 按照我們的常識,java程序一般都需要啟動時候加載類文件,如果像JSP這樣修改完代碼,不用重啟就生效,那么我們就不用這么痛苦的查bug,直接加代碼又不用發,加日志看下就解決了。其實是JSP的運行機制和java不一樣,當我們打開瀏覽器,請求一個JSP文件有如下流程:

  • JSP文件修改后,之所以能及時生效,是因為tomcate會檢查請求的JSP文件是否被更改過。如果發送過更改,呢么就會將JSP文件重新解析,翻譯成一個新的java,從而產生新的servlet類,加載到jvm中。

  • 但是此處有一個問題,根據java類加載機制,同一個classLoader中,類是不允許重復的。為繞開這個限制,Tomcate每次會創建一個新的ClassLoader實例,來加載新編譯的servlet類。之后的請求都會有這個新的Servlet來處理,這樣就實現了新舊JSP的切換。

  • HTTP服務是無狀態的,所以JSP的場景基本上是一次性消費,請求后給當前解析后的jsp內容,這種通過ClassLoader來替換class的方法在JSP上可行,因為有一個翻譯過程,但是在Spring應用中,對象大多是單例,存在內存中,就算創建新ClassLoader也要全部在處理一次,不太現實,所有這種方式在Spring項目中不可行。

  • BTrace 插樁

java 對象行為
  • java對象使用兩種東西來描述事物: 方法,屬性
    • java對象的屬性跟著對象走,每個對象存儲一份
    • java對象的方法,函數存儲在方法區
  • 如上圖:
    • 方法區中數據是類加載時候從class文件中取出
    • class文件是從java或者其他符號jvm規范的源碼中編譯來的
    • 源碼我們我們可以自己控制
  • 通過上面幾個步驟我們能否找到辦法去修改需要加載的類,從而達到我們的目的,并且需要滿足幾個條件:
    • 需要修改字節碼中目標方法所在區域,然后重新加載這個類
    • 只修改調用方法,不修改對象的屬性,也不印象已經存在的對象狀態
    • 不違背jvm類加載原理,也就是這個類還是這個類,還是同一個ClassLoader
  • 還真有:java.lang.instrument.Instrumentation
Instrumentation
  • 我們來查一下Java API中對這個類的描述信息:
該類提供了用于設計Java編程語言代碼所需的服務。 儀器是向方法添加字節碼,用于收集工具要使用的數據。 由于這些更改純粹是加法的,因此這些工具不會修改應用程序的狀態或行為。 這種良性工具的示例包括監視代理,剖析器,覆蓋分析器和事件記錄器。
  • 文檔描述中有兩個我們能用得到的方法:redefineClasses和retransformClasses。一個重新定義class,一個修改class。這兩個差不多功能,
// 使用提供的類文件重新定義提供的一組類。 void redefineClasses(ClassDefinition... definitions)throws ClassNotFoundException,UnmodifiableClassException //重新轉換提供的一組類。 void retransformClasses(<?>... classes)throws UnmodifiableClassException
  • 兩個方法都是替換已經存在的class文件,redefineClasses是自己提供字節碼文件替換已經存在的class,retransformClasses是在已經存在的字節碼文件上修改后在替換。
  • 既然JDK提供了這種API,那么我們可以在編譯得到class文件后,在通過redefineClass替換,就能加日志,修改class文件,從而達到上文中不重啟修改的目的。
直接操作字節碼
  • 我們通過JDK的api來修改了本要加載的一個Class字節碼文件,字節碼文件也是程序語言,只不過人類不好理解,可讀性遠沒有java代碼高。
  • 一般人都不會去直接修改字節碼文件,但是,有一部分杰出的程序員,創造出來可以直接編輯字節碼的框架,提供接口可以讓我們方便的去操作字節碼文件,進行注入修改類的方法,動態創造一個新的類等等操作。其中最著名的就是ASM,現在我們接觸的cglib,Spring等框架中對字節碼的操作就是基于ASM上的,
實現方式
  • 截止目前都是針對開始遇到的問題的理論層面的可行性研究,那么我們怎么實現,而且修改線上的字節碼文件簡直就是在作死,而且實施起來會有意想不到的困難:

    • 尋找工程中的這個字節碼
    • 修改這個字節碼,然后reTransform這個字節碼
    • 我們無法預知某個程序出錯需要去修改字節碼,也不可能每個工程都開發一段專門的程序去修改字節碼,并且重新加載改代碼,這樣成本太高
    • 即使我們能解決上面的問題,我們也不一定會用ASM,需要更通用的辦法
    • JVM不在本地,在遠程,我們也是需要解決的問題
    • 修改線上JVM中字節碼文件簡直在作死,這存在巨大的安全性問題
  • 幸運的是,已經有人吧這么都搞定了,因為有一個開源工具BTrace的存在,描述非常精煉:

A safe, dynamic tracing tool for the Java platform
  • BTrace 是基于Java預約的一個安全,可提供動態追蹤服務的工具。BTrace基于ASM,Java Attach API, Instruments開發,為用戶提供很多注解,依靠這些注解,可以編寫BTrace腳本(簡單的Java腳本)達到我們的目的,而不必對ASM有深刻理解。

  • 我們看下Attach 的api

  • 看BTrace官網的一個簡單例子:攔截所有java.io包中所有類以read開頭的方法,打印類名,方法名,參數名。當程序IO負載比較高的時候,可以從輸出的信息看到是哪些類引起的,如此的方便:

package com.sun.btrace.samples;import com.sun.btrace.annotations.*; import com.sun.btrace.AnyType; import static com.sun.btrace.BTraceUtils.*;/*** This sample demonstrates regular expression* probe matching and getting input arguments* as an array - so that any overload variant* can be traced in "one place". This example* traces any "readXX" method on any class in* java.io package. Probed class, method and arg* array is printed in the action.*/ @BTrace public class ArgArray {@OnMethod(clazz="/java\\.io\\..*/",method="/read.*/")public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {println(pcn);println(pmn);printArray(args);} }
先理解在應用
  • 既然BTrace能解決以上的問題,那么他是怎么做到的,他的架構是怎么樣的,我們可以從管網的信息中找到答案:

  • BTrace主要有一下幾個模塊

    • BTrace腳本:利用BTrace定義的注解,我們可以很方便的更具需要進行腳本開發
    • Compiler(編譯):將BTrace腳本編譯成BTrace class文件
    • Client:將Class文件發送到Agent
    • Agent:基于Java的Attach Api,Agent可以動態附著一個運行的JVM上,然后開啟一個BTrace Server,接受Client發過來的BTrace腳本。解析腳本然后根據腳本中的規則找到要修改的類;然后調用Java Instruments的reTransform接口完成對象行為的修改并使之生效。

安全性
  • 如上流程最終借助Java instruments 和Java Attach api實現class替換,出于安全考慮,instruments在使用上會有諸多的限制:
    • 不允許創建對象
    • 不允許創建數組
    • 不允許拋異常
    • 不允許catch異常
    • 不允許隨意調用其他對象或者類的方法,只允許調用com.sun.btrace.BTraceUtils中提供的靜態方法(一些數據處理和信息輸出工具)
    • 不允許改變類的屬性
    • 不允許有成員變量和方法,只允許存在static public void方法
    • 不允許有內部類、嵌套類
    • 不允許有同步方法和同步塊
    • 不允許有循環
    • 不允許隨意繼承其他類(當然,java.lang.Object除外)
    • 不允許實現接口
    • 不允許使用assert
    • 不允許使用Class對象
  • 如此多的限制,其實可以理解。BTrace要做的是,雖然修改了字節碼,但是除了輸出需要的信息外,對整個程序的正常運行并沒有影響。
應用
  • 應用詳見本人git項目
Arthas
  • BTrace腳本使用上也有一定學習成本,如果吧常用功能封裝好,提供簡單命令,那就編程了Archas
最后
  • 總結我們之前的知識點,Java的Instruments給運行時的動態追蹤留下了一個初始APi,Attach API則給運行時動態追蹤提供了“出入口”,ASM則大大方便了“人類”操作Java字節碼的操作。
  • 所以基于以上JDK api,前輩們創造出來諸如JProfiler, JVisualvm,BTrace,Archas這樣的工具。
  • 以上大大提高了軟件開發人民定位問題的效率。

總結

以上是生活随笔為你收集整理的Java动态追踪技术--BTrace的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。