zoukankan      html  css  js  c++  java
  • Cglib动态代理实现原理

    Cglib动态代理实现原理:
    我们先通过一个demo看一下Cglib是如何实现动态代理的。

    首先定义个服务类,有两个方法并且其中一个方法用final来修饰。

    public class PersonService {
    public PersonService() {
    System.out.println("PersonService构造");
    }
    //该方法不能被子类覆盖
    final public Person getPerson(String code) {
    System.out.println("PersonService:getPerson>>"+code);
    return null;
    }

    public void setPerson() {
    System.out.println("PersonService:setPerson");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Cglib是无法代理final修饰的方法的,具体原因我们一会通过源码来分析。

    然后,定义一个自定义MethodInterceptor。

    public class CglibProxyIntercepter implements MethodInterceptor {
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("执行前...");
    Object object = methodProxy.invokeSuper(sub, objects);
    System.out.println("执行后...");
    return object;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    我们看一下intercept方法入参,sub:cglib生成的代理对象,method:被代理对象方法,objects:方法入参,methodProxy:代理方法

    最后,我们写个例子调用一下,并将Cglib生成的代理类class文件输出磁盘方便我们反编译查看源码。

    public class Test {
    public static void main(String[] args) {
    //代理类class文件存入本地磁盘
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\code");
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(PersonService.class);
    enhancer.setCallback(new CglibProxyIntercepter());
    PersonService proxy= (PersonService) enhancer.create();
    proxy.setPerson();
    proxy.getPerson("1");
    } }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    我们执行一下会发现getPerson因为加final修饰并没有被代理,下面我们通过源码分析一下。

    执行前…
    PersonService:setPerson
    执行后…
    PersonService:getPerson>>1

    生成代理类
    执行Test测试类可以得到Cglib生成的class文件,一共有三个class文件我们反编译以后逐个说一下他们的作用。
    在这里插入图片描述

    PersonService$$EnhancerByCGLIB$$eaaaed75就是cglib生成的代理类,它继承了PersonService类。

    public class PersonService$$EnhancerByCGLIB$$eaaaed75
    extends PersonService
    implements Factory
    {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;//拦截器
    private static final Method CGLIB$setPerson$0$Method;//被代理方法
    private static final MethodProxy CGLIB$setPerson$0$Proxy;//代理方法
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$finalize$1$Method;
    private static final MethodProxy CGLIB$finalize$1$Proxy;
    private static final Method CGLIB$equals$2$Method;
    private static final MethodProxy CGLIB$equals$2$Proxy;
    private static final Method CGLIB$toString$3$Method;
    private static final MethodProxy CGLIB$toString$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1()
    {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    CGLIB$emptyArgs = new Object[0];
    Class localClass1 = Class.forName("com.demo.proxy.cglib.PersonService$$EnhancerByCGLIB$$eaaaed75");//代理类
    Class localClass2;//被代理类PersionService
    Method[] tmp95_92 = ReflectUtils.findMethods(new String[] { "finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
    CGLIB$finalize$1$Method = tmp95_92[0];
    CGLIB$finalize$1$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "finalize", "CGLIB$finalize$1");
    Method[] tmp115_95 = tmp95_92;
    CGLIB$equals$2$Method = tmp115_95[1];
    CGLIB$equals$2$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
    Method[] tmp135_115 = tmp115_95;
    CGLIB$toString$3$Method = tmp135_115[2];
    CGLIB$toString$3$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
    Method[] tmp155_135 = tmp135_115;
    CGLIB$hashCode$4$Method = tmp155_135[3];
    CGLIB$hashCode$4$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$4");
    Method[] tmp175_155 = tmp155_135;
    CGLIB$clone$5$Method = tmp175_155[4];
    CGLIB$clone$5$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    tmp175_155;
    Method[] tmp223_220 = ReflectUtils.findMethods(new String[] { "setPerson", "()V" }, (localClass2 = Class.forName("com.demo.proxy.cglib.PersonService")).getDeclaredMethods());
    CGLIB$setPerson$0$Method = tmp223_220[0];
    CGLIB$setPerson$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "setPerson", "CGLIB$setPerson$0");
    tmp223_220;
    return;
    }

    //代理方法(methodProxy.invokeSuper会调用)
    final void CGLIB$setPerson$0() {
    super.setPerson();
    }

    //被代理方法(methodProxy.invoke会调用,这就是为什么在拦截器中调用methodProxy.invoke会死循环,一直在调用拦截器)
    public final void setPerson() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if(this.CGLIB$CALLBACK_0 == null) {
    CGLIB$BIND_CALLBACKS(this);
    var10000 = this.CGLIB$CALLBACK_0;
    }

    if(var10000 != null) {
    //调用拦截器
    var10000.intercept(this, CGLIB$setPerson$0$Method, CGLIB$emptyArgs, CGLIB$setPerson$0$Proxy);
    } else {
    super.setPerson();
    }
    }
    ..........//省略部分方法的代理
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    我们通过代理类的源码可以看到,代理类会获得所有在父类继承来的方法,并且会有MethodProxy与之对应,比如 Method CGLIB$setPerson$0$Method、MethodProxy CGLIB$setPerson$0$Proxy;

    调用过程:代理对象调用this.setPerson方法->调用拦截器->methodProxy.invokeSuper->CGLIB$setPerson$0->被代理对象setPerson方法

    MethodProxy
    拦截器MethodInterceptor中就是由MethodProxy的invokeSuper方法调用代理方法的,MethodProxy非常关键,我们分析一下它具体做了什么。

    创建MethodProxy

    public class MethodProxy {
    private Signature sig1;
    private Signature sig2;
    private MethodProxy.CreateInfo createInfo;
    private final Object initLock = new Object();
    private volatile MethodProxy.FastClassInfo fastClassInfo;
    //c1:被代理对象Class
    //c2:代理对象Class
    //desc:入参类型
    //name1:被代理方法名
    //name2:代理方法名
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
    MethodProxy proxy = new MethodProxy();
    proxy.sig1 = new Signature(name1, desc);//被代理方法签名
    proxy.sig2 = new Signature(name2, desc);//代理方法签名
    proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
    return proxy;
    }
    private static class CreateInfo {
    Class c1;
    Class c2;
    NamingPolicy namingPolicy;
    GeneratorStrategy strategy;
    boolean attemptLoad;

    public CreateInfo(Class c1, Class c2) {
    this.c1 = c1;
    this.c2 = c2;
    AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
    if(fromEnhancer != null) {
    this.namingPolicy = fromEnhancer.getNamingPolicy();
    this.strategy = fromEnhancer.getStrategy();
    this.attemptLoad = fromEnhancer.getAttemptLoad();
    }

    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    invokeSuper调用

    public Object invokeSuper(Object obj, Object[] args) throws Throwable {

    try {
    this.init();
    MethodProxy.FastClassInfo fci = this.fastClassInfo;
    return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException var4) {
    throw var4.getTargetException();
    }
    }
    private static class FastClassInfo {
    FastClass f1;//被代理类FastClass
    FastClass f2;//代理类FastClass
    int i1; //被代理类的方法签名(index)
    int i2;//代理类的方法签名

    private FastClassInfo() {
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    上面代码调用过程就是获取到代理类对应的FastClass,并执行了代理方法。还记得之前生成三个class文件吗?

    PersonService$$EnhancerByCGLIB$$eaaaed75$$FastClassByCGLIB$$355cb7ea.class就是代理类的FastClass,
    PersonService$$FastClassByCGLIB$$a076b035.class就是被代理类的FastClass。
    1
    2
    FastClass机制
    Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。
    这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。下面我们反编译一个FastClass看看:

    //根据方法签名获取index
    public int getIndex(Signature var1) {
    String var10000 = var1.toString();
    switch(var10000.hashCode()) {
    case -2077043409:
    if(var10000.equals("getPerson(Ljava/lang/String;)Lcom/demo/pojo/Person;")) {
    return 21;
    }
    break;
    case -2055565910:
    if(var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
    return 12;
    }
    break;
    case -1902447170:
    if(var10000.equals("setPerson()V")) {
    return 7;
    }
    break;
    //省略部分代码.....
     
    //根据index直接定位执行方法
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
    eaaaed75 var10000 = (eaaaed75)var2;
    int var10001 = var1;

    try {
    switch(var10001) {
    case 0:
    return new Boolean(var10000.equals(var3[0]));
    case 1:
    return var10000.toString();
    case 2:
    return new Integer(var10000.hashCode());
    case 3:
    return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
    case 4:
    return var10000.newInstance((Callback)var3[0]);
    case 5:
    return var10000.newInstance((Callback[])var3[0]);
    case 6:
    var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
    return null;
    case 7:
    var10000.setPerson();
    return null;
    case 8:
    var10000.setCallbacks((Callback[])var3[0]);
    return null;
    case 9:
    return var10000.getCallback(((Number)var3[0]).intValue());
    case 10:
    return var10000.getCallbacks();
    case 11:
    eaaaed75.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
    return null;
    case 12:
    eaaaed75.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
    return null;
    case 13:
    return eaaaed75.CGLIB$findMethodProxy((Signature)var3[0]);
    case 14:
    return var10000.CGLIB$toString$3();
    case 15:
    return new Boolean(var10000.CGLIB$equals$2(var3[0]));
    case 16:
    return var10000.CGLIB$clone$5();
    case 17:
    return new Integer(var10000.CGLIB$hashCode$4());
    case 18:
    var10000.CGLIB$finalize$1();
    return null;
    case 19:
    var10000.CGLIB$setPerson$0();
    return null;
    //省略部分代码....
    } catch (Throwable var4) {
    throw new InvocationTargetException(var4);
    }

    throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    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;
    }
    }
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    至此,Cglib动态代理的原理我们就基本搞清楚了,代码细节有兴趣可以再研究下。
    最后我们总结一下JDK动态代理和Gglib动态代理的区别:
    1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
    2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
    3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。

  • 相关阅读:
    ztree学习---将默认勾选的展开
    CentOS之RPM
    CentOS之文档的压缩与打包
    CentOS之Vim
    CentOS用户和用户组管理
    Linux CentOS更改文件的权限
    CentOS的文件属性:命令 ls -l
    CentOS命令
    Java解析excel
    easyUI的combotree的树的懒加载。
  • 原文地址:https://www.cnblogs.com/hyhy904/p/10958538.html
Copyright © 2011-2022 走看看