java-動態(tài)追蹤技術

JSP動態(tài)解析過程

請求訪問一個JSP文件的時候,整個過程是這樣的:
JSP文件修改過后,之所以能及時生效,是因為Web容器(Tomcat)會檢查請求的JSP文件是否被更改過,如果發(fā)生過更改,那么就將JSP文件重新解析翻譯成一個新的Sevlet類,并加載到JVM中,之后的請求,都會由這個新的Servet來處理。這里有個問題,根據(jù)Java的類加載機制,在同一個ClassLoader中,類是不允許重復的,為了繞開這個限制,Web容器每次都會創(chuàng)建一個新的ClassLoader實例,來加載新編譯的Servlet類,之后的請求都會由這個新的Servlet來處理,這樣就實現(xiàn)了新舊JSP的切換。

HTTP服務是無狀態(tài)的,所以JSP的場景基本上都是一次性消費,這種通過創(chuàng)建新的ClassLoader來“替換”class的做法行得通,但是對于其他應用,比如Spring框架,即便這樣做了,對象多數(shù)是單例,對于內(nèi)存中已經(jīng)創(chuàng)建好的對象,我們無法通過這種創(chuàng)建新的ClassLoader實例的方法來修改對象行為。

java.lang.instrument.Instrumentation

看完文檔之后,我們發(fā)現(xiàn)這么兩個接口:reDefineClasses和reTransformClasses。一個是重新定義class,一個是修改class。

直接操作字節(jié)碼 ASM、CGLib

BTrace

https://github.com/btraceio/btrace
BTrace是基于Java語言的一個安全的、可提供動態(tài)追蹤服務的工具。BTrace基于ASM、Java Attach Api、Instruments開發(fā),為用戶提供了很多注解。依靠這些注解,我們可以編寫B(tài)Trace腳本(簡單的Java代碼)達到我們想要的效果,而不必深陷于ASM對字節(jié)碼的操作中不可自拔。


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);
    }
}

package com.sun.btrace.samples;

import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.Export;

/**
 * This sample creates a jvmstat counter and
 * increments it everytime Thread.start() is
 * called. This thread count may be accessed
 * from outside the process. The @Export annotated
 * fields are mapped to jvmstat counters. The counter
 * name is "btrace." +  + "." + 
 */ 
@BTrace public class ThreadCounter {

    // create a jvmstat counter using @Export
    @Export private static long count;

    @OnMethod(
        clazz="java.lang.Thread",
        method="start"
    ) 
    public static void onnewThread(@Self Thread t) {
        // updating counter is easy. Just assign to
        // the static field!
        count++;
    }

    @OnTimer(2000) 
    public static void ontimer() {
        // we can access counter as "count" as well
        // as from jvmstat counter directly.
        println(count);
        // or equivalently ...
        println(Counters.perfLong("btrace.com.sun.btrace.samples.ThreadCounter.count"));
    }
}

BTrace的架構是怎樣的呢?

BTrace主要有下面幾個模塊:

  • BTrace腳本:利用BTrace定義的注解,我們可以很方便地根據(jù)需要進行腳本的開發(fā)。

  • Compiler:將BTrace腳本編譯成BTrace class文件。

  • Client:將class文件發(fā)送到Agent。

  • Agent:基于Java的Attach Api,Agent可以動態(tài)附著到一個運行的JVM上,然后開啟一個BTrace Server,接收client發(fā)過來的BTrace腳本;解析腳本,然后根據(jù)腳本中的規(guī)則找到要修改的類;修改字節(jié)碼后,調(diào)用Java Instrument的reTransform接口,完成對對象行為的修改并使之生效。

Ref:

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容