Arthas 可視化被 CGLIB 動態代理後的新類

歡迎訪問陳同學博客原文

有小夥伴問:“Spring 中被 CGLIB 動態代理後的新類究竟是什麼樣子?能不能反編譯出來看看?”。

確實,親眼看看被動態代理後的新類有助於理解知識。

本篇就藉助於阿里 Arthas 反編譯內存中 class 來做個簡單演示。

Demo

下面是寫在 Spring Boot 應用中的一個 Controller,beans 接口返回所有bean,hello() 方法被 @Transactional 註解標記後,類會自動被動態代理以進行聲明式事務的處理。

package com.example;

@RestController
public class HelloController implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @GetMapping("beans")
    public Object getBeans() {
        return applicationContext.getBean("");
    }

    @Transactional
    public void hello() {
        System.out.println("hello");
    }
}

啓動應用後,訪問 beans 拿到 helloController

{
    "bean": "helloController",
    "aliases": [],
    "scope": "singleton",
    "type": "com.example.HelloController$$EnhancerBySpringCGLIB$$2d4c54bd",
    "resource": "file [.../target/classes/com/example/HelloController.class]",
    "dependencies": []
}

bean 的類型是被代理後的新類:com.example.HelloController$$EnhancerBySpringCGLIB$$2d4c54bd,從名字中的 EnhancerBySpringCGLIB 可以看出由 SpringCGLIB 進行增強。

從內存反編譯class

下載 arthas-boot.jar 後,本地直接運行jar包:**java -jar arthas-boot.jar **。

然後利用其 jad 即java decompile 命令直接反編譯內存中的class。

jad com.example.HelloController$$EnhancerBySpringCGLIB$$2d4c54bd

下面是部分截圖,可以直接拷貝到IDEA中查看更多信息。

[外鏈圖片轉存失敗(img-ki0KHlJO-1564881619722)(https://imgcdn.chenyongjun.vip/2019/07/27/1.png)]

新類繼承自HelloController,實現了 SpringProxy、Advised。再看看 HelloController 中 hello() 方法處理情況。

public class HelloController$$EnhancerBySpringCGLIB$$2d4c54bd
extends HelloController
implements SpringProxy,
Advised,
Factory {
    
    final void CGLIB$hello$1() {
        super.hello();
    }
    
    public final void hello() {
        try {
            MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
            ...
            if (methodInterceptor != null) {
                Object object = methodInterceptor.intercept(...);
                return;
            }
            // 最終調用父類方法
            super.hello();
            return;
        }
        catch ...
    }
}

子類 override 了 hello() 方法,且在其中嵌入了方法攔截。

DynamicAdvisedInterceptor 實現了 MethodInterceptor,它會執行一個攔截器鏈,而 Spring 的 TransactionInterceptor 是攔截器中一員,負責加入事務處理機制。

附:CGLIB底層基於ASM來操作字節碼,從而實現上述的動態創建新類,達到動態代理的效果。


歡迎關注公衆號 [陳一樂],一起學習,一起成長

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章