CGLIB详细讲解

        动态代理作为Spring中重要的一个技术,实现了AOP的动态代理,本文基于java的CGLIB动态代理对该技术的实现进行深入的了解。

        测试代码如下所示:

// 客户端代码
public class TestCglib {

    public static void main(String[] args) {
        //该设置用于输出cglib动态代理产生的类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\cglibClass");
        Enhancer enhancer = new Enhancer();
        //继承被代理类
        enhancer.setSuperclass(URLController.class);
        //设置回调
        enhancer.setCallback(new URLRequestMethodInterceptor());
        //生成代理类对象
        URLController urlController = (URLController)enhancer.create();
        //在调用代理类中方法时会被我们实现的方法拦截器进行拦截
        urlController.urlRequest1();
        urlController.urlRequest2();

    }

}



// 目标类
public class URLController {

    public void urlRequest1() {
        System.out.println("now request url1 ...");
        try {
            Thread.sleep(1000);
        }catch (Exception e){
        }
    }

    public void urlRequest2() {
        System.out.println("now request url2 ...");
        try {
            Thread.sleep(2000);
        }catch (Exception e){
        }
    }
}



import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 拦截器类,用于被代理类回调
public class URLRequestMethodInterceptor implements MethodInterceptor {

    public Object intercept(Object obj, Method method, Object[] arg,
        MethodProxy proxy) throws Throwable {
        System.out.println("before:"+method.getName());
        Object object = proxy.invokeSuper(obj, arg);
        System.out.println("after:"+method.getName());
        return object;
    }

}
复制代码
  1. 创建Enhancer对象

                                                      图 1-1 客户端创建Enhancer对象

                                         图 1-2 执行EnhanceKeyr的静态变量初始化

                                         图 1-3 执行KeyFactory的第一个create方法

                                         图 1-4 执行KeyFactory的第二个create方法

                                         图1-5 执行KeyFactory的第三个create方法

        第三个create方法里面,会自己创建Generator对象,用于生成Enhancer字节码文件。

                                            图1-6 执行 Generator的create方法来创建Enhancer类

        keyInterface.getName()的值为net.sf.cglib.proxy.Enhancer$EnhancerKey

                                                图1-7 生成代理类字节码文件

  •         getClassName方法是命名规则函数,Enhancer$EnhancerKey$$KeyFactory

ByCGLIB$$7fb24d72的名称则是这个方法生成的。

  •    cache2是一个hashMap结构,有两个元素。第一个元素的key为String类型的“net.sf.cglib.proxy.EnhancerEnhancerKey,值为WeakReference对象;第二个元素的key为的Object类型的对象,值为HashSet对象。刚开始时候初始化的时候,key为的Object类型的对象,值为HashSet对象(无用标记),又由于获取不到keyString类型的“net.sf.cglib.proxy.EnhancerEnhancerKey”,值为WeakReference对象;第二个元素的key为的Object类型的对象,值为HashSet对象。刚开始时候初始化的时候,key为的Object类型的对象,值为HashSet对象(无用标记),又由于获取不到key为String类型的“net.sf.cglib.proxy.EnhancerEnhancerKey“的Map,则创建Class类型的net.sf.cglib.proxy.Enhancer$EnhancerKey的引用, 该引用是WeakReference类型。

    private Set getClassNameCache(ClassLoader loader) {
    // NAME_KEY = new Object();初始化
    return (Set)((Map)source.cache.get(loader)).get(NAME_KEY);
    }

  •  ReflectUtils生成代理类在虚拟机中,即Class对象(net.sf.cglib.proxy.EnhancerEnhancerKey)。通过Genarator(实现AbstractClassGenerator)来生成Enhancer并实现AbstractClassGenerator),代理类为net.sf.cglib.proxy.EnhancerEnhancerKey)。通过Genarator(实现AbstractClassGenerator)来生成Enhancer并实现AbstractClassGenerator),代理类为net.sf.cglib.proxy.EnhancerEnhancerKeyKeyFactoryByCGLIBKeyFactoryByCGLIB7fb24d72,生成该字节码文件并加入到虚拟机中。

                                              图1-7 创建Enhancer对象

         此时生成Enhancer$EnhancerKeyKeyFactoryByCGLIBKeyFactoryByCGLIB7fb24d72对象,路径是\net\sf\cglib\proxy,变量KeyFactory初始化结束,也就是Emhancer对象创建完成。

2 生成代理类字节码文件

                                       图1-8 客户端创建目标类的代理类

                                        图1-8 执行Enhancer对象创建代理对象的过程

        此时,代理类字节码文件已经生成,并且已经加载到java虚拟机里面。

(3)代理类创建对象(生成MethodProxy类和MethodProxy对象)

        和之前创建Enhancer对象一样,生成目标类的代理类对象,生成对象之后会进行一些初始化操作,打开class源码文件,如下所示:

                                                   图1-9 代理类的字节码文件

        从上面的初始化代码可以看出,用目标类对象来初始化Method对象,用代理类的对象来初始化MethodProxy对象,目标类的每个方法对应一个Method对象,代理类的每个方法对应一个MethodPoxy对象。

                                    图 1-10 目标类方法对应的代理类方法

        从代理类的方法可以知道,调用方法最终会调用MethodInterceptor的intercept(Object obj, Method method, Object[] arg,MethodProxy proxy)方法。该方法会调用methodProxy.invokerSuper方法,源码如下:

  public Object invokeSuper(Object obj, Object[] args) throws Throwable { 
   	try { 
   	   // 处理FastClass相关的配置
   	   init(); 
   	   // 获取FastClassInfo对象fci 
   	   FastClassInfo fci = fastClassInfo; 
   	   // fci方法调用,f2是代理类的方法,i2是代理类方法索引 
   	   return fci.f2.invoke(fci.i2, obj, args); 
   	 } catch (InvocationTargetException e) { 
   	    throw e.getTargetException(); 
   	 } 
   }
复制代码

        从上面的methodProxy的源码可以看出,首先给代理类创建FastClass类(减少反射时候的耗时问题),用于加快方法调用的时间,每次调用时如果存在FastClass时,直接根据索引调用相应的方法会比反射机制快不少。调用代理类的CGLIBurlRequest1urlRequest10方法,该方法调用super.urlRequest1()方法,最终成功调用目标类的方法(代理类的父类);注意:FastClass类只有invoke方法,代理类没有。MethodProxy类有invoke和invokeSuper方法。

        如果MethodInterceptor的intercept(Object obj, Method method, Object[] arg,MethodProxy proxy)方法调用methodProxy.invoker方法,则会产生循环调用的问题。源码如下所示:

         methodProxy.invoker方法会调用FastClass目标类的方法(fci.f1.invoke(fci.i1,obj,args)),FastClass目标类的invoke方法会先把代理类强制转换成目标类,然后使用switch语句获取调用的方法var10000.urlRequest1(),最终调用的还是目标类的方法,又回调用拦截器,造成死循环。目标类的FastClass的invoke方法如下所示:

代理类的fastClass的invoke方法如下所示:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享