有小伙伴问:"Spring 中被 CGLIB 动态代理后的新类究竟是什么样子?能不能反编译出来看看?"。
确实,亲眼看看被动态代理后的新类有助于理解知识。
本篇就借助于阿里 Arthas 反编译内存中 class 来做个简单演示。
下面是写在 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 进行增强。
下载 arthas-boot.jar 后,本地直接运行jar包: java -jar arthas-boot.jar 。
然后利用其 jad 即java decompile 命令直接反编译内存中的class。
jad com.example.HelloController$$EnhancerBySpringCGLIB$$2d4c54bd
下面是部分截图,可以直接拷贝到IDEA中查看更多信息
新类继承自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来操作字节码,从而实现上述的动态创建新类,达到动态代理的效果。
推荐阅读