参考
1、介绍了 Cglib的生成的3个动态代理类源码结构, FastClass机制
https://www.cnblogs.com/monkey0307/p/8328821.html
2、通过从 MethodProxy的invokeSuper方法执行的过程来了解Cglib动态代理执行过程
https://www.cnblogs.com/yangming1996/p/6824249.html
概述
-
JDK 动态代理类的生成的机制有个鲜明的特点是: 某个类必须有实现的接口, 而生成的代理类也只能代理某个类接口定义的方法, 如果某个类没有实现接口,那么这个类就不能用JDK产生动态代理了!
-
Cglib 可以通过继承的方式实现动态代理,Cglib通过扫描该类以及其父类中所有的 public 非 final修饰的方法,通过 asm 定义该类的子类字节码,其中该子类重写了父类所有的方法,然后返回该子类的实例作为代理类。也就是说我们的 Cglib是用该类的子类作为代理类来实现代理操作的。当然 Cglib的缺点也是呼之欲出,对于被代理类中的非 public或者 final修饰的方法,不能实现代理。
1、使用方式
MethodInterceptor#intercept方法参数说明: Object obj:被代理的原对象 Method method:被调用的当前方法 Object[] args:该方法的参数集合 MethodProxy proxy:被调用方法的代理,它可以和 method完成同样的事情,但是它使用 FastClass机制非反射执行方法,效率高
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("这里是对目标类进行增强!!!" + method.getName());
//注意这里的方法调用,不是用反射哦!!!
Object object = proxy.invokeSuper(obj, args);
return object;
}
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "java_workapace");
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(OrderServiceImpl.class);
//设置回调函数
enhancer.setCallback(new MyMethodInterceptor());
//这里的creat方法就是正式创建代理类
OrderServiceImpl proxyDog = (OrderServiceImpl)enhancer.create();
//调用代理类的eat方法
proxyDog.test1("xoiaoming");
}
}
2、原理介绍
2.1、获取 Cglib 生成的代理类对象 & FastClass
通过设置系统变量可以保存生成代理类的字节码 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "java_workapace");
Cglib 动态代理过程生成了三个字节码文件
- OrderServiceImpl?EnhancerByCGLIB?e4b0590d?FastClassByCGLIB?cf8aae5d.class
- OrderServiceImpl?EnhancerByCGLIB?e4b0590d.class
- OrderServiceImpl?FastClassByCGLIB?97d766be.class
OrderServiceImpl?EnhancerByCGLIB?e4b0590d.class 是增加代理类对象,继承了被代理类OrderServiceImpl。类中含有被代理了的方法 & 父类中方法的调用,被重写了方法名字。 test1()、CGLIB$test1$2
OrderServiceImpl?EnhancerByCGLIB?e4b0590d?FastClassByCGLIB?cf8aae5d.class、OrderServiceImpl?FastClassByCGLIB?97d766be.class都是对代理类OrderServiceImpl?EnhancerByCGLIB?e4b0590d.class 中的方法索引
OrderServiceImpl?EnhancerByCGLIB?e4b0590d?FastClassByCGLIB?cf8aae5d.class FastClass类: 含有被代理方法&非代理方法的方法索引 test1()、CGLIB$test1$97d766be.class FastClass类: 只还有被代理方法的索引 test1()
2.2、FastClass机制
Cglib 动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是: 为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。 这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。
1、通过反编译 OrderServiceImpl?FastClassByCGLIB?97d766be.class、OrderServiceImpl?EnhancerByCGLIB?e4b0590d?FastClassByCGLIB?cf8aae5d.class FastClassl类查看类结构
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1147862635:
if (var10000.equals("test2()V")) {
return 0;
}
break;
case 992023936:
if (var10000.equals("test1(Ljava/lang/String;)V")) {
return 1;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 2;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 3;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 4;
}
}
return -1;
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
OrderServiceImpl var10000 = (OrderServiceImpl)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.test2();
return null;
case 1:
var10000.test1((String)var3[0]);
return null;
case 2:
return new Boolean(var10000.equals(var3[0]));
case 3:
return var10000.toString();
case 4:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
2、FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
//MethodProxy invoke/invokeSuper都调用了init()
private void init() {
if(this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if(this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);//如果缓存中就取出,没有就生成新的FastClass
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);//获取方法的index
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
2.3、Cglib 代理类分析
1、通过反编译 代理类 OrderServiceImpl?EnhancerByCGLIB?e4b0590d.class 分析。 在代理类中 继承被代理的方法例:test3(), 是通过回调方法来执行 ##在enhancer.setCallback(new MyMethodInterceptor())设置。 父类中的方法生成了一个 CGLIB$test3$1()方法去调用。
final void CGLIB$test3$1() {
super.test3();
}
public final void test3() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$test3$1$Method, CGLIB$emptyArgs, CGLIB$test3$1$Proxy);
} else {
super.test3();
}
}
2、进入 org.springframework.cglib.proxy.MethodInterceptor#intercept 方法后, 通过 org.springframework.cglib.proxy.MethodProxy#invokeSuper 执行被代理类方法。
3、MethodProxy 持有代理类、被代理类的信息FastClassInfo, 通过FastClass执行方法
private static class FastClassInfo {
FastClass f1;// FastClass: OrderServiceImpl$$FastClassByCGLIB$$97d766be.class, 只含有代理中被增强方法的索引
FastClass f2;// FastClass: OrderServiceImpl$$EnhancerByCGLIB$$e4b0590d$$FastClassByCGLIB$$cf8aae5d.class
int i1; // 被代理类的方法签名 test1
int i2;// 未被代理类的方法签名 CGLIB$test1$2
private FastClassInfo() {
}
}
2.4、invokeSuper()、invoke() 区别
MethodProxy#invokeSuper 方法执行代理类中的被重写名字的调用父类方法(未被增强的方法), MethodProxy.FastClassInfo#f2 执行 CGLIB$test2$0()方法 MethodProxy#invoke 方法执行代理的类中 重写父类的方法(被增强的方法), MethodProxy.FastClassInfo#f1 执行 test2()方法
final void CGLIB$test2$0() {
super.test2();
}
public final void test2() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
} else {
super.test2();
}
}
在重写 com.wl.springbootdemo.demo.dynamic.cglib.MyMethodInterceptor#intercept 方法时, 需要使用 invokeSuper()方法执行, 否则会一直死循环