歡迎訪問陳同學博客原文
有小夥伴問:“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來操作字節碼,從而實現上述的動態創建新類,達到動態代理的效果。
歡迎關注公衆號 [陳一樂],一起學習,一起成長