精华内容
下载资源
问答
  • cglib动态代理实现原理
    2019-05-17 14:03:48

    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");
        }
    }
    

    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;
        }
    }
    

    我们看一下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"); 
        } }
    

    我们执行一下会发现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();
              }
           }
           ..........//省略部分方法的代理
    }
    

    我们通过代理类的源码可以看到,代理类会获得所有在父类继承来的方法,并且会有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();
            }
    
        }
    }
    

    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() {
        }
    }
    

    上面代码调用过程就是获取到代理类对应的FastClass,并执行了代理方法。还记得之前生成三个class文件吗?

    PersonService$$EnhancerByCGLIB$$eaaaed75$$FastClassByCGLIB$$355cb7ea.class就是代理类的FastClass, 
    PersonService$$FastClassByCGLIB$$a076b035.class就是被代理类的FastClass。
    

    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");
       }
    

    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;
                    }
                }
            }
    
        }
    

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

    原文链接:https://www.cnblogs.com/monkey0307/p/8328821.html

    更多相关内容
  • 代理模式;jdk实现动态代理CGLib实现动态代理;jdk与CGLib的区别

    一.代理模式概念

    代理模式:给原对象提供一个代理对象,让代理对象直接控制对原对象的引用.用生活中的话来说,代理对象就是中介.

    作用:保护原对象;可以增加原对象的功能.
    静态代理:在编译时就获得代理对象,这叫静态代理.
    动态代理:在运行时通过反射获得代理对象,叫动态代码.
    注意:AOP的底层用的是动态代理.
    代理图解

    二.jdk实现动态代理:必须依赖原对象的父接口

    下面代码举例说明:
    有一个男孩想找女朋友

    /**
    * 男孩的业务父接口
    * @auth ljc
    */
    public interface BoyFriendService {
        /**
         * 寻找女朋友的方法
         */
        public void findGirlFriend();
    }
    

    他有一个正在找女朋友的方法

    /**
    * 男孩的业务实现类
    * @auth ljc
    */
    public class BoyFriendServiceImpl  implements BoyFriendService{
        /**
         * 寻找女朋友的方法
         */
        @Override
        public void findGirlFriend() {
            System.out.println("正在寻找女朋友...");
        }
    }
    

    但总是找不到,于是他找了个媒婆帮他找
    媒婆就是他的代理,媒婆跟女孩说
    我这一个优质男孩(前置增强:在切点(原方法)执行之前执行增强处理代码)
    正在寻找女朋友…(执行原方法)
    他有八套房,一辆劳斯莱斯幻影(后置增强:在切点(原方法)执行之后执行增强处理代码.)

    /**
    * jdk动态代理处理类
    * @auth ljc
    */
    public class JdkProxy implements  InvocationHandler {
        /**
         * 声明被代理的对象
         */
        Object target;
        /**
         * 通过构造方法将原对象传过来
         * @param ob
         */
        public JdkProxy(Object ob){
            this.target=ob;
        }
        /**
         * 代理方法
         * @param proxy 原对象的代理对象
         * @param method 原方法的反射对象
         * @param args 原方法的参数列表
         * @return Object
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy,  Method method, Object[] args) throws  Throwable {
            System.out.println("我这一个优质男孩");
            //用原方法的反射对象调用原方法
            Object result=  method.invoke(target,args);
            System.out.println("他有八套房,一辆劳斯莱斯幻影");
            return result;
        }
    }
    

    但这媒婆有一个缺点,就是男孩女孩两人见面,必须要男孩他爹来,不然不给面

    /**
    * 测试类
    * @auth ljc
    */
    public class JkdTest1{
    	public static void main(String[] args) {
        	//创建原对象
        	BoyFriendService boyFriend=new  BoyFriendServiceImpl();
        	//创建jdk动态代理的处理器
        	JdkProxy jdkProxy=new  JdkProxy(boyFriend);
        	//创建jdk代理对象,第一个参数是类加载器,第二个参数是原对象的父接口反射对象,第三个参数是动态代理处理对象
        	BoyFriendService boyFriendProxy=  (BoyFriendService)  Proxy.newProxyInstance(JkdTest1.class.getClassLoader(),boyFriend.getClass().getInterfaces(),jdkProxy);
        	//用jdk代理对象调用方法
        	boyFriendProxy.findGirlFriend();
    	}
    }
    

    三.CGLib实现动态代理

    **GCLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑.** 还是刚才那个例子: 有个靓仔正在找靓妹
    /**
    * 男孩的业务实现类
    * @auth ljc
    */
    public class BoyFriendServiceImpl  implements BoyFriendService{
        /**
         * 寻找女朋友的方法
         */
        @Override
        public void findGirlFriend() {
            System.out.println("正在寻找女朋友...");
        }
    }
    

    他找了一个媒婆
    媒婆跟女孩说
    我这一个优质男孩(前置增强:在切点(原方法)执行之前执行增强处理代码)
    正在寻找女朋友…(执行原方法)
    他有八套房,一辆劳斯莱斯幻影(后置增强:在切点(原方法)执行之后执行增强处理代码.)

    /**
    * cglib动态代码的处理类
    * @auth ljc 
    */
    public class CgLibProxy implements  MethodInterceptor {
        /**
         * 声明原类的子类对象
         */
        public Enhancer en=new Enhancer();
        /**
         * 声明一个方法获得cglib动态代码的子类的代理对象
         * @param clazz 原对象的反射对象
         * @return Object
         */
        public Object getCgLibProxy(Class  clazz){
            //将原类设为子类对象的处器对象的父类
            en.setSuperclass(clazz);
            //将当前处理器类的对象设为子类处器对象
            en.setCallback(this);
            //通过子类对象的创建子类的代理对象
            return en.create();
        }
        /**
         * 代理方法
         * @param o 原对象
         * @param method 子类方法反射对象
         * @param objects  方法参数
         * @param methodProxy 代理对象的代理方法反射对象
         * @return Object
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o,  Method method, Object[] objects,  MethodProxy methodProxy) throws Throwable  {
            System.out.println("我这一个优质男孩");
            //调用原方法
            Object result=  methodProxy.invokeSuper(o,objects);
            System.out.println("他有八套房,一辆劳斯莱斯幻影");
            return result;
        }
    }
    

    但不同的是,媒婆不找男孩他爹了,她给男孩找了个儿子(编不下去了,哈哈哈,有违常理)

    /**
    * 测试类
    * @auth ljc
    */
    public class JkdTest1{
    	public static void main(String[] args) {
        	//创建处理器对象
       		CgLibProxy cgLibProxy=new CgLibProxy();
        	//获得原类的子类的代理对象
        	BoyFriendServiceImpl boyFriendProxy=  (BoyFriendServiceImpl)  cgLibProxy.getCgLibProxy(BoyFriendServiceImpl.class);
        	//用子类的代理对象调用原类的方法
        	boyFriendProxy.findGirlFriend();
    	}
    }
    

    四.JDK动态代理和CGLIB代理的区别

    1. JDK动态代理依赖于类的父接口生成代理,而不能针对类
    CGLIB是针对类实现代理,可以指定的类生成一个子类,覆盖其中的方法(继承)

    2.Spring在选择用JDK还是CGLiB代理时是看Bean有没有实现接口;实现接口了,Spring用JDK的动态代理;没有实现接口,Spring就用CGlib代理

    展开全文
  • 【Spring基础】CGLIB动态代理实现原理

    万次阅读 多人点赞 2018-06-09 18:11:19
    前言 ... 一 CGLIB介绍 CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库, 它可以在运行期扩展Java类与实现...Hibernate用它来实现PO(Persistent Object 持久化对象)...

    前言

    Github:https://github.com/yihonglei/thinking-in-spring(spring工程)

    一 CGLIB介绍

    CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

    它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

    方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

    除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,

    因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    二 CGLIB动态代理实例

    实现一个业务类,注意,这个业务类并没有实现任何接口:

    package com.jpeony.spring.proxy.cglib;
    
    public class HelloService {
    
        public HelloService() {
            System.out.println("HelloService构造");
        }
    
        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        final public String sayOthers(String name) {
            System.out.println("HelloService:sayOthers>>"+name);
            return null;
        }
    
        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
    }
    

    自定义MethodInterceptor:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    /**
     * 自定义MethodInterceptor
     */
    public class MyMethodInterceptor implements MethodInterceptor{
    
        /**
         * sub:cglib生成的代理对象
         * method:被代理对象方法
         * objects:方法入参
         * methodProxy: 代理方法
         */
        @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;
        }
    }

    生成CGLIB代理对象调用目标方法:

    package com.jpeony.spring.proxy.cglib;
    
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
    
    public class Client {
        public static void main(String[] args) {
            // 代理类class文件存入本地磁盘方便我们反编译查看源码
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(HelloService.class);
            // 设置enhancer的回调对象
            enhancer.setCallback(new MyMethodInterceptor());
            // 创建代理对象
            HelloService proxy= (HelloService)enhancer.create();
            // 通过代理对象调用目标方法
            proxy.sayHello();
        }
    }

    运行结果:

    三 CGLIB动态代理源码分析

    实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:

    /*
     * Copyright 2002,2003 The Apache Software Foundation
     *
     *  Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package net.sf.cglib.proxy;
    
    /**
     * General-purpose {@link Enhancer} callback which provides for "around advice".
     * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
     * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
     */
    public interface MethodInterceptor
    extends Callback
    {
        /**
         * All generated proxied methods call this method instead of the original method.
         * The original method may either be invoked by normal reflection using the Method object,
         * or by using the MethodProxy (faster).
         * @param obj "this", the enhanced object
         * @param method intercepted Method
         * @param args argument array; primitive types are wrapped
         * @param proxy used to invoke super (non-intercepted method); may be called
         * as many times as needed
         * @throws Throwable any exception may be thrown; if so, super method will not be invoked
         * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
         * @see MethodProxy
         */    
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
    
    }
    

    这个接口只有一个intercept()方法,这个方法有4个参数:

    1)obj表示增强的对象,即实现这个接口类的一个对象;

    2)method表示要被拦截的方法;

    3)args表示要被拦截方法的参数;

    4)proxy表示要触发父类的方法对象;

    在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:

    /**
         * Generate a new class if necessary and uses the specified
         * callbacks (if any) to create a new object instance.
         * Uses the no-arg constructor of the superclass.
         * @return a new instance
         */
        public Object create() {
            classOnly = false;
            argumentTypes = null;
            return createHelper();
        }

    该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,

    使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:

    private Object createHelper() {
            preValidate();
            Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                    ReflectUtils.getNames(interfaces),
                    filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                    callbackTypes,
                    useFactory,
                    interceptDuringConstruction,
                    serialVersionUID);
            this.currentKey = key;
            Object result = super.create(key);
            return result;
        }

    preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。

    通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法

    创建代理对象的参数。

    protected Object create(Object key) {
            try {
                ClassLoader loader = getClassLoader();
                Map<ClassLoader, ClassLoaderData> cache = CACHE;
                ClassLoaderData data = cache.get(loader);
                if (data == null) {
                    synchronized (AbstractClassGenerator.class) {
                        cache = CACHE;
                        data = cache.get(loader);
                        if (data == null) {
                            Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                            data = new ClassLoaderData(loader);
                            newCache.put(loader, data);
                            CACHE = newCache;
                        }
                    }
                }
                this.key = key;
                Object obj = data.get(this, getUseCache());
                if (obj instanceof Class) {
                    return firstInstance((Class) obj);
                }
                return nextInstance(obj);
            } catch (RuntimeException e) {
                throw e;
            } catch (Error e) {
                throw e;
            } catch (Exception e) {
                throw new CodeGenerationException(e);
            }
        }

    真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

    abstract protected Object nextInstance(Object instance) throws Exception;

    在子类Enhancer中实现,实现源码如下:

    protected Object nextInstance(Object instance) {
            EnhancerFactoryData data = (EnhancerFactoryData) instance;
    
            if (classOnly) {
                return data.generatedClass;
            }
    
            Class[] argumentTypes = this.argumentTypes;
            Object[] arguments = this.arguments;
            if (argumentTypes == null) {
                argumentTypes = Constants.EMPTY_CLASS_ARRAY;
                arguments = null;
            }
            return data.newInstance(argumentTypes, arguments, callbacks);
        }

    看看data.newInstance(argumentTypes, arguments, callbacks)方法,

    第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

    最后根据这些参数,通过反射生成代理对象,源码如下:

    /**
             * Creates proxy instance for given argument types, and assigns the callbacks.
             * Ideally, for each proxy class, just one set of argument types should be used,
             * otherwise it would have to spend time on constructor lookup.
             * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
             * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
             *
             * @see #createUsingReflection(Class)
             * @param argumentTypes constructor argument types
             * @param arguments constructor arguments
             * @param callbacks callbacks to set for the new instance
             * @return newly created proxy
             */
            public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
                setThreadCallbacks(callbacks);
                try {
                    // Explicit reference equality is added here just in case Arrays.equals does not have one
                    if (primaryConstructorArgTypes == argumentTypes ||
                            Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
                        // If we have relevant Constructor instance at hand, just call it
                        // This skips "get constructors" machinery
                        return ReflectUtils.newInstance(primaryConstructor, arguments);
                    }
                    // Take a slow path if observing unexpected argument types
                    return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
                } finally {
                    // clear thread callbacks to allow them to be gc'd
                    setThreadCallbacks(null);
                }
    
            }

    最后生成代理对象:

    将其反编译后代码如下:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.jpeony.spring.proxy.cglib;
    
    import java.lang.reflect.Method;
    import net.sf.cglib.core.ReflectUtils;
    import net.sf.cglib.core.Signature;
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.Factory;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class HelloService$$EnhancerByCGLIB$$be45efdd extends HelloService implements Factory {
        private boolean CGLIB$BOUND;
        public static Object CGLIB$FACTORY_DATA;
        private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
        private static final Callback[] CGLIB$STATIC_CALLBACKS;
        private MethodInterceptor CGLIB$CALLBACK_0;
        private static Object CGLIB$CALLBACK_FILTER;
        private static final Method CGLIB$sayHello$0$Method;
        private static final MethodProxy CGLIB$sayHello$0$Proxy;
        private static final Object[] CGLIB$emptyArgs;
        private static final Method CGLIB$equals$1$Method;
        private static final MethodProxy CGLIB$equals$1$Proxy;
        private static final Method CGLIB$toString$2$Method;
        private static final MethodProxy CGLIB$toString$2$Proxy;
        private static final Method CGLIB$hashCode$3$Method;
        private static final MethodProxy CGLIB$hashCode$3$Proxy;
        private static final Method CGLIB$clone$4$Method;
        private static final MethodProxy CGLIB$clone$4$Proxy;
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$be45efdd");
            Class var1;
            Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
            CGLIB$equals$1$Method = var10000[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = var10000[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = var10000[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = var10000[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
            CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.jpeony.spring.proxy.cglib.HelloService")).getDeclaredMethods())[0];
            CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
        }
    
        final void CGLIB$sayHello$0() {
            super.sayHello();
        }
    
        public final void sayHello() {
            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$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
            } else {
                super.sayHello();
            }
        }
    
        final boolean CGLIB$equals$1(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$2() {
            return super.toString();
        }
    
        public final String toString() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
        }
    
        final int CGLIB$hashCode$3() {
            return super.hashCode();
        }
    
        public final int hashCode() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
                return var1 == null ? 0 : ((Number)var1).intValue();
            } else {
                return super.hashCode();
            }
        }
    
        final Object CGLIB$clone$4() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
        }
    
        public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
            String var10000 = var0.toString();
            switch(var10000.hashCode()) {
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$4$Proxy;
                }
                break;
            case 1535311470:
                if (var10000.equals("sayHello()V")) {
                    return CGLIB$sayHello$0$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$1$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$2$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$3$Proxy;
                }
            }
    
            return null;
        }
    
        public HelloService$$EnhancerByCGLIB$$be45efdd() {
            CGLIB$BIND_CALLBACKS(this);
        }
    
        public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
            CGLIB$THREAD_CALLBACKS.set(var0);
        }
    
        public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
            CGLIB$STATIC_CALLBACKS = var0;
        }
    
        private static final void CGLIB$BIND_CALLBACKS(Object var0) {
            HelloService$$EnhancerByCGLIB$$be45efdd var1 = (HelloService$$EnhancerByCGLIB$$be45efdd)var0;
            if (!var1.CGLIB$BOUND) {
                var1.CGLIB$BOUND = true;
                Object var10000 = CGLIB$THREAD_CALLBACKS.get();
                if (var10000 == null) {
                    var10000 = CGLIB$STATIC_CALLBACKS;
                    if (var10000 == null) {
                        return;
                    }
                }
    
                var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
            }
    
        }
    
        public Object newInstance(Callback[] var1) {
            CGLIB$SET_THREAD_CALLBACKS(var1);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            HelloService$$EnhancerByCGLIB$$be45efdd var10000 = new HelloService$$EnhancerByCGLIB$$be45efdd;
            switch(var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
        public Callback getCallback(int var1) {
            CGLIB$BIND_CALLBACKS(this);
            MethodInterceptor var10000;
            switch(var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
            }
    
            return var10000;
        }
    
        public void setCallback(int var1, Callback var2) {
            switch(var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
            }
        }
    
        public Callback[] getCallbacks() {
            CGLIB$BIND_CALLBACKS(this);
            return new Callback[]{this.CGLIB$CALLBACK_0};
        }
    
        public void setCallbacks(Callback[] var1) {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        }
    
        static {
            CGLIB$STATICHOOK1();
        }
    }
    

    重点关注代理对象的sayHello方法:

    从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,

    intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中

    的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

    JDK动态代理实现原理(jdk8)

     

    展开全文
  • 一、CGLIB介绍 CGLIB(Code Generation ...Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。 CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他...

    一、CGLIB介绍

    CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

    CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供方法interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

    二、CGLIB动态代理实例


    (1) 实现一个业务类,注意,这个业务类并没有实现任何接口:
     

    package com.lanhuigu.spring.proxy.cglib;
     
    public class HelloService {
    
        public HelloService() {
            System.out.println("HelloService:构造函数执行");
        }
    
        public void sayHello(){
            System.out.println("HelloService:Hello World!");
        }
    
        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        public final void sayOther(String name){
            System.out.println("HelloService: Hello "+name);
        }
    
    }
    
    

    (2) 自定义方法拦截器(拦截目标类所有可继承方法, 并进行增强修改):

    package com.lanhuigu.spring.proxy.cglib;
     
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
     
    import java.lang.reflect.Method;
     
    /**
     * 自定义MethodInterceptor
     */
    public class MyMethodInterceptor implements MethodInterceptor{
     
        /**
         * sub:cglib生成的代理对象
         * method:被代理对象方法
         * objects:方法入参
         * methodProxy: 代理方法
         */
        @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;
        }
    }

    (3) 生成CGLIB代理对象调用目标方法:

    package com.lanhuigu.spring.proxy.cglib;
     
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
     
    public class Client {
        public static void main(String[] args) {
            // 代理类class文件存入本地磁盘方便我们反编译查看源码
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(HelloService.class);
            // 设置enhancer的回调对象
            enhancer.setCallback(new MyMethodInterceptor());
            // 创建代理对象
            HelloService proxy= (HelloService)enhancer.create();
            // 通过代理对象调用目标方法
            proxy.sayHello();
            //sayOther()方法被final关键字修饰, 将不会被拦截增强
            proxy.sayOther("小明");
        }
    }
    

     

    运行结果:

     

    三、CGLIB动态代理源码分析

    实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:

    /*
     * Copyright 2002,2003 The Apache Software Foundation
     *
     *  Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     *  Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package net.sf.cglib.proxy;
     
    /**
     * General-purpose {@link Enhancer} callback which provides for "around advice".
     * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
     * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
     */
    public interface MethodInterceptor
    extends Callback
    {
        /**
         * All generated proxied methods call this method instead of the original method.
         * The original method may either be invoked by normal reflection using the Method object,
         * or by using the MethodProxy (faster).
         * @param obj "this", the enhanced object
         * @param method intercepted Method
         * @param args argument array; primitive types are wrapped
         * @param proxy used to invoke super (non-intercepted method); may be called
         * as many times as needed
         * @throws Throwable any exception may be thrown; if so, super method will not be invoked
         * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
         * @see MethodProxy
         */    
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
     
    }

     

    这个接口只有一个intercept()方法,这个方法有4个参数:

    1. obj: 增强的对象,即实现这个接口类的一个对象,也就是cglib生成的代理对象;
    2. method: 被拦截的方法;
    3. args: 被拦截方法的参数;
    4. proxy: 被拦截方法的方法对象;

    在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:
     

    /**
     * Generate a new class if necessary and uses the specified
     * callbacks (if any) to create a new object instance.
     * Uses the no-arg constructor of the superclass.
     * @return a new instance
     */
     public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
     }

    该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,

    使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:

    private Object createHelper() {
            preValidate();
            Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                    ReflectUtils.getNames(interfaces),
                    filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                    callbackTypes,
                    useFactory,
                    interceptDuringConstruction,
                    serialVersionUID);
            this.currentKey = key;
            Object result = super.create(key);
            return result;
        }

    preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。

    通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法

    创建代理对象的参数。
     

    protected Object create(Object key) {
            try {
                ClassLoader loader = getClassLoader();
                Map<ClassLoader, ClassLoaderData> cache = CACHE;
                ClassLoaderData data = cache.get(loader);
                if (data == null) {
                    synchronized (AbstractClassGenerator.class) {
                        cache = CACHE;
                        data = cache.get(loader);
                        if (data == null) {
                            Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                            data = new ClassLoaderData(loader);
                            newCache.put(loader, data);
                            CACHE = newCache;
                        }
                    }
                }
                this.key = key;
                Object obj = data.get(this, getUseCache());
                if (obj instanceof Class) {
                    return firstInstance((Class) obj);
                }
                return nextInstance(obj);
            } catch (RuntimeException e) {
                throw e;
            } catch (Error e) {
                throw e;
            } catch (Exception e) {
                throw new CodeGenerationException(e);
            }
        }

    真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

    abstract protected Object nextInstance(Object instance) throws Exception;

    在子类Enhancer中实现,实现源码如下:
     

    protected Object nextInstance(Object instance) {
            EnhancerFactoryData data = (EnhancerFactoryData) instance;
     
            if (classOnly) {
                return data.generatedClass;
            }
     
            Class[] argumentTypes = this.argumentTypes;
            Object[] arguments = this.arguments;
            if (argumentTypes == null) {
                argumentTypes = Constants.EMPTY_CLASS_ARRAY;
                arguments = null;
            }
            return data.newInstance(argumentTypes, arguments, callbacks);
        }

    看看data.newInstance(argumentTypes, arguments, callbacks)方法,

    第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

    最后根据这些参数,通过反射生成代理对象,源码如下:

    /**
             * Creates proxy instance for given argument types, and assigns the callbacks.
             * Ideally, for each proxy class, just one set of argument types should be used,
             * otherwise it would have to spend time on constructor lookup.
             * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
             * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
             *
             * @see #createUsingReflection(Class)
             * @param argumentTypes constructor argument types
             * @param arguments constructor arguments
             * @param callbacks callbacks to set for the new instance
             * @return newly created proxy
             */
            public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
                setThreadCallbacks(callbacks);
                try {
                    // Explicit reference equality is added here just in case Arrays.equals does not have one
                    if (primaryConstructorArgTypes == argumentTypes ||
                            Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
                        // If we have relevant Constructor instance at hand, just call it
                        // This skips "get constructors" machinery
                        return ReflectUtils.newInstance(primaryConstructor, arguments);
                    }
                    // Take a slow path if observing unexpected argument types
                    return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
                } finally {
                    // clear thread callbacks to allow them to be gc'd
                    setThreadCallbacks(null);
                }
     
            }

    最后生成代理对象:

     

    将其反编译后代码如下(将class文件放在项目的target目录下再打开即可反编译):

    package com.lanhuigu.spring.proxy.cglib;
     
    import java.lang.reflect.Method;
    import net.sf.cglib.core.ReflectUtils;
    import net.sf.cglib.core.Signature;
    import net.sf.cglib.proxy.*;
     
    public class HelloService$$EnhancerByCGLIB$$4da4ebaf extends HelloService
    	implements Factory
    {
     
    	private boolean CGLIB$BOUND;
    	public static Object CGLIB$FACTORY_DATA;
    	private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    	private static final Callback CGLIB$STATIC_CALLBACKS[];
    	private MethodInterceptor CGLIB$CALLBACK_0; // 拦截器
    	private static Object CGLIB$CALLBACK_FILTER;
    	private static final Method CGLIB$sayHello$0$Method; // 被代理方法
    	private static final MethodProxy CGLIB$sayHello$0$Proxy; // 代理方法
    	private static final Object CGLIB$emptyArgs[];
    	private static final Method CGLIB$equals$1$Method;
    	private static final MethodProxy CGLIB$equals$1$Proxy;
    	private static final Method CGLIB$toString$2$Method;
    	private static final MethodProxy CGLIB$toString$2$Proxy;
    	private static final Method CGLIB$hashCode$3$Method;
    	private static final MethodProxy CGLIB$hashCode$3$Proxy;
    	private static final Method CGLIB$clone$4$Method;
    	private static final MethodProxy CGLIB$clone$4$Proxy;
     
    	static void CGLIB$STATICHOOK1()
    	{
    		Method amethod[];
    		Method amethod1[];
    		CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    		CGLIB$emptyArgs = new Object[0];
    		// 代理类
    		Class class1 = Class.forName("com.lanhuigu.spring.proxy.cglib.HelloService$$EnhancerByCGLIB$$4da4ebaf");
    		// 被代理类
    		Class class2;
    		amethod = ReflectUtils.findMethods(new String[] {
    			"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"
    		}, (class2 = Class.forName("java.lang.Object")).getDeclaredMethods());
    		Method[]  = amethod;
    		CGLIB$equals$1$Method = amethod[0];
    		CGLIB$equals$1$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
    		CGLIB$toString$2$Method = amethod[1];
    		CGLIB$toString$2$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
    		CGLIB$hashCode$3$Method = amethod[2];
    		CGLIB$hashCode$3$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$3");
    		CGLIB$clone$4$Method = amethod[3];
    		CGLIB$clone$4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
    		amethod1 = ReflectUtils.findMethods(new String[] {
    			"sayHello", "()V"
    		}, (class2 = Class.forName("com.lanhuigu.spring.proxy.cglib.HelloService")).getDeclaredMethods());
    		Method[] 1 = amethod1;
    		CGLIB$sayHello$0$Method = amethod1[0];
    		CGLIB$sayHello$0$Proxy = MethodProxy.create(class2, class1, "()V", "sayHello", "CGLIB$sayHello$0");
    	}
     
    	final void CGLIB$sayHello$0()
    	{
    		super.sayHello();
    	}
     
    	public final void sayHello()
    	{
    	  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.sayHello();
          }
    	}
    	......
    	......
    }

    从代理对象反编译源码可以知道,代理对象继承于HelloService,拦截器调用intercept()方法,intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

    展开全文
  • cglib动态代理实现及其原理浅析

    千次阅读 2022-03-22 18:18:42
    JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的...
  • cglib动态代理实现原理详细分析

    千次阅读 2019-01-01 18:29:08
    在上篇JDK动态代理实现原理详细分析中,对其JDK代理的流程做了一个详细的分析。而本文,将介绍另一种动态代理模式:cglib动态代理。阅读完本文,你将对cglib代理模式的运行的流程有一个清晰的认识。 本文的目录如下:...
  • 动态代理是 AOP(Aspect Orient Programming)编程思想,理解...CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法代理final对象与final方法。(final类型不能有子类,final方法不能被重载)
  • CGLIB 动态代理及其原理分析

    千次阅读 2021-02-01 15:29:52
    它可以在运行期扩展 Java 类与实现 Java 接口(JDK 动态代理只能用于接口),它被许多 AOP 框架广泛地使用,如为 Spring AOP 提供方法的 interception(拦截),被 Hibernate 用来代理单端(多对一和一对一)关联...
  • CGLib动态代理原理

    2021-12-02 22:36:08
    CGLib动态代理原理 CGLib动态代理代理类去继承目标类,然后重写其中目标类的方法啊,这样也可以保证代理类拥有目标类的同名方法; 看一下CGLib的基本结构,下图所示,代理类去继承目标类,每次调用代理类的方法...
  • jdk动态代理的局限性 首先我们知道,使用jdk创建动态代理有个局限,就是他只能为接口创建代理实例,对于那些没有实现接口的业务类,就不能使用jdk动态代理了;所以我们就需要使用CGLib动态代理。...CGLib动态代理实现
  • 接口和实现子类 package com.adtchengdu.proxy; public interface Targertinterface { public void save(); } package com.adtchengdu.proxy; public class Target implements Targertinterface{ @Override...
  • 文章目录一、基本代理知识了解①静态代理②jdk动态代理cglib动态代理二.jdk动态代理cglib动态代理的共同点?三.jdk动态代理是怎么生成代理对象的? 本文解决一下几个问题: 1.jdk动态代理cglib动态代理的共同点...
  • cglib 动态代理详解 我们都知道jdk的动态代理内部调用切面无效的问题,而cglib则不会出现这种情况,这是为什么?cglib就一定不会出现内部调用切面无效的问题吗?cglib针对每一个类只创建了一个代理类吗?为什么cglib...
  • JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的...
  • 熟悉Spring AOP的一定知道,AOP的实现是基于java动态代理和cglib代理两种方法实现的。 (看源码会知道,在进入准备生成代理对象阶段会有一个if条件判断,如下) 要代理对象实现了接口,默认情况下会采用JDK的...
  • 基于MAVEN项目的CGLib动态代理原理实现
  • JDK与Cglib动态代理区别与原理前言一、嵌套方法二、原理分析 前言 如题的区别,大多数同学第一回答基本都是JDK的动态代理需要被代理实现接口,而Cglib动态代理无须这个要求,由于继承所以无法代码初final修饰的类...
  • 接口: public interface UserService { void save(); void delete(); void update();...实现类: public class UserServiceImpl implements UserService { @Override public void save() { Sys...
  • CGLib动态代理实现

    千次阅读 2018-10-09 00:26:01
    使用JDK创建动态代理有一个限制, 即它只能为接口创建代理实例. 对于没有定义接口的业务方法的类, 使用CDGlib 进行动态代理. CGLib是一个强大的, 高性能的代码生成库. 被广泛应用于 AOP 框架. 用以提供方法拦截...
  • 我们先通过一个demo看一下Cglib是如何实现动态代理的。 首先定义个服务类,有两个方法并且其中一个方法用final来修饰。 public class PersonService { public PersonService() { System.out.println(...
  • 动态代理听过的有jdk的动态代理以及cglib动态代理。究竟这两种代理方式有什么区别,好奇研究了下。 jdk动态代理示例 这里举个简单的例子,普通人要买票,但是自己买票一般都买不到的,于是,可以让黄牛代为买票...
  • 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能...下面我们讲讲jdk动态代理和cglib动态代理实现及区别 cglib动态代理
  • Cglib动态代理实现方式 我们先通过一个demo看一下Cglib是如何实现动态代理的。 首先定义个服务类,有两个方法并且其中一个方法用final来修饰。 public class PersonService { public PersonService() { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,666
精华内容 13,066
关键字:

cglib动态代理实现原理