提示:动态代理
文章目录
前言
类型 | 机制 | 回调方式 | 适用场景 | 效率 |
---|---|---|---|---|
JDK动态代理 | 委托机制。代理类和目标类都实现了同样的接口。InvocationHandler持有目标类。代理类委托InvocationHandler去调用目标类原始方法 | 反射 | 目标类实现接口 | 反射调用稍慢。 |
CGLIB动态代理 | 继承机制。代理类继承了目标类并重写了目标方法,通过回调函数MethodInterceptor调用父类方法执行原始逻辑 | 通过FastClass方法索引调用 | 非final类,非final方法 | 第一次调用因为要生成多个Class对象较]DK慢,但是调用时方法索引较反射方式快 |
本篇讲解通过FastClass方法索引调用
中FastClass机制原理。
一、FastClass机制
JDK动态代理的拦截对象是通过反射的机制来调用被拦截方法的,反射的效率比较低,所以CGLIB采用了FastClass的机制来实现对被拦截方法的调用。
CGLIB共生成3个类,分别为代理类,代理类的FastClass,目标类的FastClass,FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法。
FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
下面用一个小例子来说明:
package com.kkk.demo1;
/**
* @author Kkk
* @date 2023/2/21
* @Describe: 演示 FastClass机制
*/
public class Test {
public static void main(String[] args){
Target target = new Target();
TargetFastClass fastClass = new TargetFastClass();
int index = fastClass.getIndex("targetMethod1()V");
fastClass.invoke(index, target, null);
}
}
/**
* 模拟代理类 如:UserService$$EnhancerByCGLIB$$1552dfb0
*/
class Target{
public void targetMethod1(){
System.out.println("...targetMethod1...");
}
public void targetMethod2(){
System.out.println("...targetMethod2...");
}
}
/**
* 模拟代理类FastClass 如:UserService$$EnhancerByCGLIB$$1552dfb0$$FastClassByCGLIB$$8d34995d
*/
class TargetFastClass{
public Object invoke(int index, Object o, Object[] arg){
Target t = (Target) o;
switch(index){
case 1:
t.targetMethod1();
return null;
case 2:
t.targetMethod2();
return null;
}
return null;
}
public int getIndex(String signature){
String var = signature.toString();
switch(var.hashCode()){
case -1709726090:
return 1;
case -1709696299:
return 2;
}
return -1;
}
}
上例中,TargetFastClass是Target的Fastclass,在TargetFastClass中有两个方法getIndex和invoke。在getIndex方法中对Target的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。Invoke根据指定的索引,以arg为入参调用对象O的方法。这样就避免了反射调用,提高了效率。
总结
拙技蒙斧正,不胜雀跃。