• Spring AOP 实现原理


     《JDK的动态代理深入解析(Proxy,InvocationHandler)(转)

    cglib简介与callback解析

    一、静态代理
      1.1、什么是静态代理
      1.2、静态代理示例说明
      1.3、静态代理缺点

    二、动态代理
      2.1、java动态代理原理
      2.2、动态代理示例说明
      2.3、JDK动态代理有以下几种特点(优缺点)
    三、 Cglib动态代理

    前面在学习代理模式的时候,了解到代理模式分为动态代理和静态代理。现在我们就以代理模式为基础先实现我们自己的AOP框架,再来研究Spring的AOP的实现原理。AOP的原理就是java的动态代理机制,下面先是对java的动态机制进行一个回顾:

    一、静态代理

    1.1、什么是静态代理

    什么是代理?代理就是给目标类提供一个代理对象,由代理对象控制目标对象的引用。
    代理有啥好处呢?①通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性,②通过代理对象对原有的业务增强。
    静态代理要求:Jdk的静态代理要求,目标对象和代理对象都要实现相同的接口。然后提供给客户端使用。这个代理对客户端是可见的。

    1.2、静态代理示例说明

    先以静态代理实现,静态代理关键是在代理对象和目标对象实现共同的接口,并且代理对象持有目标对象的引用。 

    public interface IHello {
         /**
          * 业务方法
          * @param str
         */
         void sayHello(String str);
     }

      目标类代码:

    public class Hello implements IHello{
         @Override
         public void sayHello(String str) {
             System.out.println("hello "+str);
         }
         
     }

      代理类代码,我们给它添加日志记录功能,在方法开始前后执行特定的方法,是不是和AOP特别像呢?

    public class ProxyHello implements IHello{  
    //目标对象
    private IHello hello;
    //通过构造方法传递目标对象
    public ProxyHello(IHello hello) { super(); this.hello = hello; } @Override public void sayHello(String str) {
    //添加特定的方法 Logger.start();
    hello.sayHello(str);
    //增强方法后 Logger.end(); } }

      日志类代码:

    public class Logger {
         public static void start(){
             System.out.println(new Date()+ " say hello start...");
         }
         
         public static void end(){
             System.out.println(new Date()+ " say hello end");
         }
     }

      测试代码:

    package com.dxz.proxy1;
    
    public class Test {
        public static void main(String[] args) {
            // 创建具体的实现类对象
            IHello target = new Hello();
            // 如果我们需要日志功能,则使用代理类,创建代理对象,并通过构造函数传递具体对象
            IHello proxy = new ProxyHello(target);
            // 执行代理对象的方法
            proxy.sayHello("明天");
        }
    }

      这样我们就实现了一个最简单的AOP,但是这样会存在一个问题:如果我们像Hello这样的类很多,那么,我们是不是要去写很多个HelloProxy这样的类呢。这样不利于程序的扩展。

    1.3、静态代理缺点

    静态代理要为每个目标类创建一个代理类,当需要代理的对象太多,那么代理类也变得很多。同时代理类违背了可重复代理只写一次的原则。

    二、动态代理

    在jdk1.3以后,jdk跟我们提供了一个API java.lang.reflect.InvocationHandler的类, 这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事。下面我们就来实现动态代理的实现。

    2.1、java动态代理原理

    在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:

    InvocationHandler:

    InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
    Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    proxy:  指代我们所代理的那个真实对象
    method:  指代的是我们所要调用真实对象的某个方法的Method对象
    args:  指代的是调用真实对象某个方法时接受的参数

    如果不是很明白,等下通过一个实例会对这几个参数进行更深的讲解。

    接下来我们来看看Proxy这个类:

    Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 

    Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
    Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

    这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

    好了,在介绍完这两个接口(类)以后,看下面的示例。

    2.2、动态代理示例说明

      接口实现与静态代理相同,代理类代码:

    public class DynaProxyHello implements InvocationHandler {
         
         private Object target;//目标对象
         /**
          * 通过反射来实例化目标对象
          * @param object
          * @return
          */
         public Object bind(Object object){
             this.target = object;
             return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
         }
         
         @Override
         public Object invoke(Object proxy, Method method, Object[] args)
                 throws Throwable {
             Object result = null;
             Logger.start();//添加额外的方法
             //通过反射机制来运行目标对象的方法
             result = method.invoke(this.target, args);
             Logger.end();
             return result;
         }
         
     }

    或者:

    public class JDKProxyFactory implements InvocationHandler {
     
        private Object target;
     
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
     
        // 创建代理对象
        public Object createProxy() {
            // 1.得到目标对象的类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
            // 2.得到目标对象的实现接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
            // 3.第三个参数需要一个实现invocationHandler接口的对象
            Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
            return newProxyInstance;
        }
     
        @Override
        // 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 增强前
            System.out.println("这是增强方法前......");
            Object invoke = method.invoke(target, args);
            // 增强后
            System.out.println("这是增强方法后......");
            return invoke;
        }
     
        public static void main(String[] args) {
            // 1.创建对象
            UserServiceImpl userService = new UserServiceImpl();
            // 2.创建代理对象
            JDKProxyFactory proxy = new JDKProxyFactory(userService);
            // 3.调用代理对象的增强方法,得到增强后的对象
            IUserService createProxy = (IUserService) proxy.createProxy();
            createProxy.regist();
        }
    }

    测试类代码:

    public class DynaTest {
         public static void main(String[] args) {
             IHello hello = (IHello) new DynaProxyHello().bind(new Hello());//如果我们需要日志功能,则使用代理类
             //IHello hello = new Hello();//如果我们不需要日志功能则使用目标类
             hello.sayHello("明天");
         }
     }

    JDK动态代理类实现了InvocationHandler接口。在重写的invoke方法中可以看出,JDK动态代理的基础是反射(method.invoke(对象,参数))Proxy.newProxyInstance(),这个方法,字面上的意思是新建一个代理类的实例,这一点就和静态代理不同了。里面的参数有三个 类加载器、所有的接口,得到InvocationHandler接口的子类实例。

    看完上面的代码可能和Spring AOP相比有一个问题,日志类只能在方法前后打印,但是AOP应该是可以在满足条件就可以执行,所有是否可以将DynaPoxyHello对象和日志操作对象(Logger)解耦呢?

    示例3

    看下面代码实现,将将DynaPoxyHello对象和日志操作对象(Logger)解耦:

      我们要在被代理对象的方法前面或者后面去加上日志操作代码(或者是其它操作的代码),那么,我们可以抽象出一个接口,这个接口里就只有两个方法:一个是在被代理对象要执行方法之前执行的方法,我们取名为start,第二个方法就是在被代理对象执行方法之后执行的方法,我们取名为end。

      Logger的接口:

    package com.dxz.dyna2;
    
    import java.lang.reflect.Method;
    
    public interface ILogger {
        void start(Method method);
    
        void end(Method method);
    }

      Logger的接口实现:

    package com.dxz.dyna2;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    
    public class DLogger implements ILogger {
        @Override
        public void start(Method method) {
            System.out.println(new Date() + method.getName() + " say hello start...");
        }
    
        @Override
        public void end(Method method) {
            System.out.println(new Date() + method.getName() + " say hello end");
        }
    }

    动态代理类:

    package com.dxz.dyna2;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class DynaProxyHello1 implements InvocationHandler {
        // 调用对象
        private Object proxy;
        // 目标对象
        private Object target;
    
        public Object bind(Object target, Object proxy) {
            this.target = target;
            this.proxy = proxy;
            return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(),
                    this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            // 反射得到操作者的实例
            Class clazz = this.proxy.getClass();
            // 反射得到操作者的Start方法
            Method start = clazz.getDeclaredMethod("start", new Class[] { Method.class });
            // 反射执行start方法
            start.invoke(this.proxy, new Object[]{method});
            // 执行要处理对象的原本方法
            method.invoke(this.target, args);
            // 反射得到操作者的end方法
            Method end = clazz.getDeclaredMethod("end", new Class[] { Method.class });
            // 反射执行end方法
            end.invoke(this.proxy, new Object[] { method });
            return result;
        }
    
    }

      测试代码:

    package com.dxz.dyna2;
    
    public class DynaTest1 {
        public static void main(String[] args) {
            IHello hello = (IHello) new DynaProxyHello1().bind(new Hello(), new DLogger());// 如果我们需要日志功能,则使用代理类
            // IHello hello = new Hello();//如果我们不需要日志功能则使用目标类
            hello.sayHello("明天");
        }
    }

      通过上面例子,可以发现通过动态代理和发射技术,已经基本实现了AOP的功能,如果我们只需要在方法执行前打印日志,则可以不实现end()方法,这样就可以控制打印的时机了。如果我们想让指定的方法打印日志,我们只需要在invoke()方法中加一个对method名字的判断,method的名字可以写在xml文件中,这样我们就可以实现以配置文件进行解耦了,这样我们就实现了一个简单的spring aop框架。

    2.3、JDK动态代理有以下几种特点(优缺点):

      1、Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷;因为它创建代理对象的时候是根据接口创建的。如果不实现接口,jdk无法给目标对象创建代理对象。被代理对象可以实现多个接口,创建代理时指定创建某个接口的代理对象就可以调用该接口定义的方法了。

      2、Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实例。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上;

      3、Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来;

      4、InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。
    JDK的动态代理深入解析(Proxy,InvocationHandler)(转)

    三、 Cglib动态代理

    cglib的全称为code generation library,是一个强大的高性能,高质量的代码生成类库,cglib封装了asm,可以在运行期动态生成新的class。

       JDK的动态代理机制只能代理实现了接口的类,而 没有实现接口的类 就不能实现JDK的动态代理,cglib是针对类来实现代理的他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理

    使用cglib为目标类提供动态代理:需要导入cglib.jar和asm.jar。如果出现asm中的类无法找到的异常,在java工程中是真的缺少asm.jar,而在web工程中很可能是asm.jar和spring提供的org.springframework.asm-3.0.4.RELEASE.jar包冲突。

    被代理类普通类(无接口)

    package com.dxz.cglib;
    
    public class BookFacade {
        public void addBook() {
            System.out.println("增加图书的普通方法...");
        }
    }
    package com.dxz.cglib;
    
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    /**
     * 使用cglib动态代理
     */
    public class BookFacadeCglib implements MethodInterceptor {
        private Object target;
    
        /**
         * 创建代理对象
         * 
         * @param target
         * @return
         */
        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(this.target.getClass());
            // 回调方法
            enhancer.setCallback(this);
            // 创建代理对象
            return enhancer.create();
        }
    
        @Override
        // 回调方法
    //参数一:代理对象; 参数二:需要增强的方法; 参数三:需要增强方法的参数; 参数四:需要增强的方法的代理
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物开始"); proxy.invokeSuper(obj, args); System.out.println("事物结束"); return null; } }
    package com.dxz.cglib;
    
    public class TestCglib {
    
        public static void main(String[] args) {
    // 1.创建对象 BookFacadeCglib cglib
    = new BookFacadeCglib();
    // 2.创建代理对象 BookFacade bookCglib
    = (BookFacade) cglib.getInstance(new BookFacade());
    // 3.调用代理对象的增强方法,得到增强后的对象 bookCglib.addBook(); } }

     结果:

    事物开始
    增加图书的普通方法...
    事物结束

    cglib原理与callback解析

    实际上,cglib基于继承实现,这也就意味着final,private相关的method无法被代理。基于asm框架对class字节码编辑改动,从而达到动态代理的目的,总之,被代理类没有实现接口的情况下cglib为首选。

    示例:如果我把上面的示例中方法改为private或final后,

    private修饰addBook方法

    public final修饰addbook方法示例:

    回来看看官方的一段话:

    字节码生成库是用于生成和转换JAVA字节码的高级API。AOP,测试,数据访问框架使用它来生成动态代理对象并拦截字段访问。

    简单的来说就是使用字节码处理框架ASM来转换字节码并生成新的需要代理类的子类,其核心就是通过继承这一个面向对象的特点来完成代理,子类需重写被代理的父类中所有非final的方法。同时在子类中采用方法拦截的技术拦截所有父类方法的调用, 顺势织入横切逻辑, 比JDK动态代理要快。但缺点是对于fianl方法无法进行代理

    CGLIB的原理是怎样的呢?我们可以在测试代码中增加一段代码,将cglib代理后的class文件写入磁盘,然后反编译来一探究竟,代码如下:

    package com.dxz.cglib;
    
    import org.assertj.core.internal.cglib.core.DebuggingClassWriter;
    
    public class PrintCglib {
    
        public static void main(String[] args) {
            
            
            //利用CGlib的代理类可以将内存中的class文件写入本地磁盘
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cglib_proxy_class");
            
            
            // 1.创建对象
            BookFacadeCglib cglib = new BookFacadeCglib();
            // 2.创建代理对象
            BookFacade bookCglib = (BookFacade) cglib.getInstance(new BookFacade());
            // 3.调用代理对象的增强方法,得到增强后的对象
            bookCglib.addBook();
        }
    }

    重新执行diam,我们发现在E://cglib_proxy_class目录下多个class文件,如下图所示:

     反编译,

    package com.dxz.cglib;
    
    import java.lang.reflect.Method;
    import org.springframework.cglib.core.ReflectUtils;
    import org.springframework.cglib.core.Signature;
    import org.springframework.cglib.proxy.Callback;
    import org.springframework.cglib.proxy.Factory;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    public class BookFacade$$EnhancerByCGLIB$$d6883e62
      extends BookFacade
      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$addBook$0$Method;
      private static final MethodProxy CGLIB$addBook$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 localClass1 = Class.forName("com.dxz.cglib.BookFacade$$EnhancerByCGLIB$$d6883e62");
        Class localClass2;
        Method[] tmp50_47 = ReflectUtils.findMethods(new String[] { "addBook", "()V" }, (localClass2 = Class.forName("com.dxz.cglib.BookFacade")).getDeclaredMethods());
        CGLIB$addBook$0$Method = tmp50_47[0];
        CGLIB$addBook$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "addBook", "CGLIB$addBook$0");
        tmp50_47;
        Method[] tmp131_128 = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = tmp131_128[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        Method[] tmp151_131 = tmp131_128;
        CGLIB$toString$2$Method = tmp151_131[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        Method[] tmp171_151 = tmp151_131;
        CGLIB$hashCode$3$Method = tmp171_151[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$3");
        Method[] tmp191_171 = tmp171_151;
        CGLIB$clone$4$Method = tmp191_171[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        tmp191_171;
      }
      
      final void CGLIB$addBook$0()
      {
        super.addBook();
      }
      
      public final void addBook()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        if (this.CGLIB$CALLBACK_0 != null) {
          return;
        }
        super.addBook();
      }
      
      final boolean CGLIB$equals$1(Object paramObject)
      {
        return super.equals(paramObject);
      }
      
      public final boolean equals(Object paramObject)
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
        {
          Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$1$Method, new Object[] { paramObject }, CGLIB$equals$1$Proxy);
          tmp41_36;
          return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
        }
        return super.equals(paramObject);
      }
      
      final String CGLIB$toString$2()
      {
        return super.toString();
      }
      
      public final String toString()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null) {
          return (String)tmp17_14.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
        }
        return super.toString();
      }
      
      final int CGLIB$hashCode$3()
      {
        return super.hashCode();
      }
      
      public final int hashCode()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
        {
          Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
          tmp36_31;
          return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
        }
        return super.hashCode();
      }
      
      final Object CGLIB$clone$4()
        throws CloneNotSupportedException
      {
        return super.clone();
      }
      
      protected final Object clone()
        throws CloneNotSupportedException
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null) {
          return tmp17_14.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
        }
        return super.clone();
      }
      
      public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature)
      {
        String tmp4_1 = paramSignature.toString();
        switch (tmp4_1.hashCode())
        {
        case -508378822: 
          if (tmp4_1.equals("clone()Ljava/lang/Object;")) {
            return CGLIB$clone$4$Proxy;
          }
          break;
        }
      }
      
      public BookFacade$$EnhancerByCGLIB$$d6883e62()
      {
        CGLIB$BIND_CALLBACKS(this);
      }
      
      public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
      {
        CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
      }
      
      public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
      {
        CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
      }
      
      private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
      {
        d6883e62 locald6883e62 = (d6883e62)paramObject;
        if (!locald6883e62.CGLIB$BOUND)
        {
          locald6883e62.CGLIB$BOUND = true;
          Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
          if (tmp23_20 == null)
          {
            tmp23_20;
            CGLIB$STATIC_CALLBACKS;
          }
          locald6883e62.CGLIB$CALLBACK_0 = (// INTERNAL ERROR //

    我们看导代理类会获得所有从父类继承来的方法,并且会有MethodProxy与之对应,比如:final void CGLIB$addBook$0()。代理方法会通过methodProxy.invokeSuper()方法会调用。

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

     更多cglib原理看《cglib简介与callback解析

    CGLIB之所以快:

    Cglib动态代理执行代理方法效率之所以比JDK高是因为Cglib采用了FastClass机制,它为代理类和被代理类各生成了一个class,这个class会为代理类与被代理类的方法分类index。这个index作为方法参数,FastClass可以直接定位到要调用的方法进行调用,这样省去了反射调用,所以效率比JDK动态代理快。FastClass不是与代理类一起生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放入缓存。

    jdk动态代理和cglib动态代理的区别

    1、jdk动态代理是实现了被代理对象的接口,cglib是继承了被代理对象。
    2、jdk和cglib都是在运行期生成字节码,jdk是直接写class字节码,cglib使用ASM框架写class字节码,cglib代理实现更复杂,生成代理类比jdk效率低。
    3、jdk调用代理方法,是通过反射机制调用,cglib是通过FastClass机制直接调用方法,cglib执行效率更高

    https://blog.csdn.net/weixin_44153058/article/details/113446909

  • 相关阅读:
    Android自动填写获取到的验证码
    java 调用mysql存储过程
    TreeMap按照key排序
    Java中的Map List Set等集合类
    Java 多线程 并发编程
    Linux查看端口、进程情况及kill进程
    采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!)
    Wix 安装部署教程(十) --来,用WPF做个漂亮的安装界面
    Jquery Mobile 小结
    岂能尽如人意,但求无愧于心
  • 原文地址:https://www.cnblogs.com/duanxz/p/2799636.html
Copyright © 2020-2023  润新知