设计模式-代理模式

定义

代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。
代理模式可以提供非常好的访问控制,应用比较广泛。
在java中一般是两种,静态代理和动态代理,动态代理又分为CGLIB和jdk自带。

代理模式通用类图:


image.png

Subject(抽象角色):通过接口或抽象类声明真实角色实现的业务方法。
RealSubject(真实角色):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
Proxy(代理角色):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

一个是真正要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。

静态代理

由程序员创建或者工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件。

  1. 抽象角色
  public interface Subject {
    /**
     * 接口方法
     */
       void request();
}
  1. 真实角色
public class ConcreteSubject implements Subject {
    /**
     * 具体的业务逻辑实现
     */
    @Override
    public void request() {
        //业务处理逻辑
    }
}
  1. 代理角色
public class Proxy implements Subject {

    /**
     * 要代理的实现类
     */
    private Subject subject = null;

    /**
     * 默认代理自己
     */
    public Proxy() {
        this.subject = new Proxy();
    }

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    /**
     * 构造函数,传递委托者
     *
     * @param objects 委托者
     */
    public Proxy(Object... objects) {
    }

    /**
     * 实现接口方法
     */
    @Override
    public void request() {
        this.before();
        this.subject.request();
        this.after();
    }

    /**
     * 预处理
     */
    private void before() {
        //do something
    }

    /**
     * 后处理
     */
    private void after() {
        //do something
    }
}

4.客户端类

public class Client {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Proxy proxy = new Proxy(subject);
        proxy.request();
    }
}

静态代理的优缺点

  • 优点
    业务类只需要关注业务逻辑本身,保证了业务类的重用性。代理使客户端不需要指定实现类是什么,怎么做的,而客户端只需指定代理即可(解耦合)。对于如上的客户端代码,Subject subject = new ConcreteSubject(); Proxy proxy = new Proxy(subject);可以应用工厂方法将它隐藏。
  • 缺点
    代理类与真实类实现了相同的接口,会出现大量重复代码。如果接口增加一个方法,除了所以类需要实现这个方法外,所以代理类也需要实现此方法。

代理对象只服务于一种类型的对象,如果要服务多类型的对象,势必要为每一种对象都进行代理。如上的代码是只为Subject类的访问提供了代理,但是如果还要为其他类如AnotherSubject类提供代理的话,就需要我们再次添加代理AnotherSubject的代理类。

由于静态代理的这个缺点,就需要使用动态代理。

动态代理(jdk)

类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。

在java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类的支持。

java.lang.reflect.InvocationHandler中最重要的方法是:

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

参数:

  • ClassLoader loader:类加载器
  • Class<?>[] interfaces:得到全部的接口
  • InvocationHandler h:得到InvocationHandler接口的子类实例
  1. 抽象角色类(必须指定一个最顶层接口)
public interface Subject {
    /**
     * 接口方法
     */
    public void request();
}
  1. 真实角色类(需要被代理的类,实现了顶层接口,非必须)
public class ConcreteSubject implements Subject {
    /**
     * 具体的业务逻辑实现
     */
    @Override
    public void request() {
        //业务处理逻辑
    }
}
  1. 动态代理对象类
@Slf4j
public class ProxyHandler implements InvocationHandler {
    /**
     * 目标对象
     */
    private Object target;

    /**
     * 绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
     *
     * @param target 绑定具体的代理实例
     * @return 动态代理类实例
     */
    public Object newProxyInstance(Object target) {
        this.target = target;
        /*
        该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例。
        第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器。
        第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口。
        第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
        根据传入的目标返回一个代理对象
        */
        Object result = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
        return result;
    }

    /**
     * 关联的这个实现类的方法被调用时将被执行。InvocationHandler接口的方法。
     *
     * @param proxy  代理
     * @param method 原对象被调用的方法
     * @param args   方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //TODO 原对象方法调用前添加的预处理逻辑

        Object ret = null;
        try {
            //调用目标方法
            ret = method.invoke(target, args);
        } catch (Exception e) {
            log.error("调用{}.{}发生异常", target.getClass().getName(), method.getName(), e);
            throw e;
        }
        //TODO 原对象方法调用后添加的后处理逻辑
        return ret;
    }
}

被代理对象target通过参数传递进来,我们通过target.getClass().getClassLoader()获取ClassLoader对象,然后通过target.getClass().getInterfaces()获取它实现的所有接口,然后将target包装到实现了InvocationHandler接口的ProxyHandler实现对象中。通过newProxyInstance函数我们就获得了一个动态代理对象。

  1. 客户端类
@Slf4j
public class Client {
    public static void main(String[] args) {
        log.info("开始");
        ProxyHandler handler = new ProxyHandler();
        Subject subject = (Subject) handler.newProxyInstance(new ConcreteSubject());
        subject.request();
        log.info("结束");
    }
}

可以看到,我们可以通过ProxyHandler代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。
当前非常流行的面向切面的编程(Aspect Oriented Programming, AOP),其核心就是动态代理机制。
备注:要实现动态代理的首要条件是被代理类必须实现一个接口,才能被代理。

jdk动态代理的优缺点

优点
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。
缺点
Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处——它始终无法摆脱仅支持 interface代理的桎梏,因为它的设计注定了这个遗憾。动态生成的代理类的继承关系图,已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。

动态代理(CGLIB)

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术,拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
更详细一点来讲:代理类将目标类作为自己的父类并为其中的每个非final委托方法创建两个方法:

  • 一个是与目标方法签名相同的方法,它在方法中会通过super调用目标方法;
  • 另一个是代理类独有的方法,称为callback回调方法,它会判断这个方法是否绑定了拦截器(实现了MethodInterceptor接口的对象),若存在则调用intercept方法对目标方法进行代理,也就是在前后加上一些增强逻辑。intercept中就会调用上面介绍的签名相同的方法。
public class ConcreteClass{
     /**
     * 具体的业务逻辑实现
     */
    public void request() {
        //业务处理逻辑
    }
}

public class CglibProxyInterceptor implements MethodInterceptor {

    public Object getProxy(Class clazz) {
        //Enhancer类是CGLib中的一个字节码增强器
        Enhancer enhancer = new Enhancer();
        //首先将目标类clazz设置为父类
        enhancer.setSuperclass(clazz);
        //然后设置拦截器CglibProxyInterceptor,也可以是多个,数组的形式enhancer.setCallbacks(cbarray)
        enhancer.setCallback(this);
        //最后执行enhancer.create()动态生成一个代理类
        return enhancer.create();
    }

    /**
     * Object:cglib生成的代理对象
     * Method:被代理对象的方法
     * Object[]:方法参数
     * MethodProxy:代理对象的方法
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行方法前dosomething。。。");
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("执行方法后dosomething。。。");
        return invoke;
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        //cglib动态代理
        CglibProxyInterceptor interceptor = new CglibProxyInterceptor();
        ConcreteClass proxy = (ConcreteClass)interceptor.getProxy(ConcreteClass.class);
        proxy.request();
    }

}

代理模式的优点

职责清晰:真实角色是实现实际的业务逻辑,不关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
高扩展性:真实角色随时发生变化,但是只要实现了接口,接口不变,代理类就可以不做任何修改,符合“开闭原则”。

名称 备注
静态代理 简单,代理模式,是动态代理的理论基础。常见使用在代理模式
jdk动态代理 需要有顶层接口才能使用,但是在只有顶层接口的时候也可以使用,使用反射、动态生成字节码技术。常见是mybatis的mapper文件是代理。
cglib动态代理 可以直接代理类,不能对 final类进行继承。使用了动态生成字节码技术。

代理模式底层怎么实现的呢?

JDK动态代理源码(jdk1.8版)

Proxy静态方法newProxyInstance

  /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * {@code IllegalArgumentException} for the same reasons that
     * {@code Proxy.getProxyClass} does.
     *
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     * @throws  IllegalArgumentException if any of the restrictions on the
     *          parameters that may be passed to {@code getProxyClass}
     *          are violated
     * @throws  SecurityException if a security manager, <em>s</em>, is present
     *          and any of the following conditions is met:
     *          <ul>
     *          <li> the given {@code loader} is {@code null} and
     *               the caller's class loader is not {@code null} and the
     *               invocation of {@link SecurityManager#checkPermission
     *               s.checkPermission} with
     *               {@code RuntimePermission("getClassLoader")} permission
     *               denies access;</li>
     *          <li> for each proxy interface, {@code intf},
     *               the caller's class loader is not the same as or an
     *               ancestor of the class loader for {@code intf} and
     *               invocation of {@link SecurityManager#checkPackageAccess
     *               s.checkPackageAccess()} denies access to {@code intf};</li>
     *          <li> any of the given proxy interfaces is non-public and the
     *               caller class is not in the same {@linkplain Package runtime package}
     *               as the non-public interface and the invocation of
     *               {@link SecurityManager#checkPermission s.checkPermission} with
     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
     *               permission denies access.</li>
     *          </ul>
     * @throws  NullPointerException if the {@code interfaces} array
     *          argument or any of its elements are {@code null}, or
     *          if the invocation handler, {@code h}, is
     *          {@code null}
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            throws IllegalArgumentException
    {
        //检查无效的对象引用
        Objects.requireNonNull(h);
        //克隆一个或多个接口
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 查找或生成指定的代理类
         * 实现动态代理的核心方法,动态代理的思路便是生成一个新类,刚刚getProxyClass0便成为了生成新类
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         * 调用指定的invocation构造函数
         * 根据生成的class通过反射获取构造函数对象并生成代理类实例
         */
        try {
            if (sm != null) {
                //校验权限
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //获取代理类的构造函数,参数类型必须是InvocationHandler(private static final Class<?>[] constructorParams = { InvocationHandler.class };)
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //构造函数不是public,则设置当前构造函数为访问权限
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //调用构造函数构造代理类实例,入参数为‘调用处理程序’的实例
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

proxyClassCache

getProxyClass0方法里其实直接取proxyClassCache缓存,如果缓存里有,直接取,如果没有,通过ProxyClassFactory创建代理对象。

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);

ProxyClassFactory
ProxyClassFactory是Proxy里的一个内部类,用来生成代理类,apply()方法 最后调用ProxyGenerator.generateProxyClass()方法来完成生成字节码的操作。

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }

        return var4;
    }

jdk生成的字节码文件

保存生成字节码文件的两种方式:

  • 启动时VM options:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true来保存生成的字节码文件
  • //该设置用于输出jdk动态代理产生的类
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.yirendai.borrowbase.node.service.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void request() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.yirendai.borrowbase.node.service.Subject").getMethod("request");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看出,动态生成的代理类有如下特性:

  1. 继承了Proxy类,实现了代理的接口,由于java不能多继承,所以jdk的动态代理不支持对实现类的代理,只支持接口的代理。
  2. 提供了一个使用InvocationHandler作为参数的构造方法。
  3. 生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。
  4. 重写了Object类的equals,hashCode,toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
  5. 实现代理接口的request方法,并调用了InvocationHandler的invoke方法。

CGLIB动态代理源码分析

enhancer.create()方法是实际创建代理实例的方法

public Object create()
  {
    this.classOnly = false;
    this.argumentTypes = null;
    return createHelper();
  }

该方法设置了两个参数配置,指定将要创建的对象不仅仅是一个类,指定参数为空。至于这两个参数的作用,还要往下看createHelper类:

  private Object createHelper()
  {
    validate();
    if (this.superclass != null) {
      setNamePrefix(this.superclass.getName());
    } else if (this.interfaces != null) {
      setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
    }
    return super.create(KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter, this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID));
  }

validate()方法主要对于一些参数进行校验
接着就做了两个判断,用于指定被创建的代理类的名称,我们暂时不管它。又到了一个核心方法,该方法将创建代理类并返回该类实例。首先我们看参数都是是什么意思,就一个参数,该参数是由KEY_FACTORY.newInstance方法返回的一个Object类型,我们看到在该方法的传入参数中,包括了父类类名或者接口名,回调类型,版本号等。该方法实际上返回了一个该代理类的一个唯一标识,这还不是关键,最关键的方法是这个create方法:

protected Object create(Object key) {
        try {
            Class gen = null;
            AbstractClassGenerator.Source var3 = this.source;
            synchronized(this.source) {
                // 获取加载器,就是Enhancer.EnhancerKey的类加载器
                ClassLoader loader = this.getClassLoader();
                Map cache2 = null;
                // 使用WeakHashMap缓存,以classLoader为key
                cache2 = (Map)this.source.cache.get(loader);
                if (cache2 == null) {
                    cache2 = new HashMap();
                    ((Map)cache2).put(NAME_KEY, new HashSet());
                    this.source.cache.put(loader, cache2);
                } else if (this.useCache) {
                    Reference ref = (Reference)((Map)cache2).get(key);
                    gen = (Class)(ref == null ? null : ref.get());
                }
                // 缓存中如果存在该代理类,则直接返回代理类对象
                if (gen == null) {
                    Object save = CURRENT.get();
                    CURRENT.set(this);

                    Object var24;
                    try {
                        this.key = key;
                        // 第一次attemptLoad为false
                        if (this.attemptLoad) {
                            try {
                                // 使用ClassLoader加载到JVM
                                gen = loader.loadClass(this.getClassName());
                            } catch (ClassNotFoundException var17) {
                                ;
                            }
                        }

                        if (gen == null) {
                            // 生成字节,经过这里attemptLoad变为true,会再次执行create(Object key)方法
                            byte[] b = this.strategy.generate(this);
                            // 生成类名称
                            String className = ClassNameReader.getClassName(new ClassReader(b));
                            // 放入缓存
                            this.getClassNameCache(loader).add(className);
                            // 反射生成代理类class
                            gen = ReflectUtils.defineClass(className, b, loader);
                        }

                        if (this.useCache) {
                            ((Map)cache2).put(key, new WeakReference(gen));
                        }
                        // 实例化代理类对象,在Enhance中执行
                        var24 = this.firstInstance(gen);
                    } finally {
                        CURRENT.set(save);
                    }

                    return var24;
                }
            }

            return this.firstInstance(gen);
        } catch (RuntimeException var20) {
            throw var20;
        } catch (Error var21) {
            throw var21;
        } catch (Exception var22) {
            throw new CodeGenerationException(var22);
        }
    }

如果usecache为为true表明该代理类已经在cache中了,直接返回引用即可。否则通过 this.strategy.generate(this);方法生成该代理类的字节码,然后通过类加载器加载该字节码生成class类型,最后通过firstInstance方法生成代理类的实例返回。

DebuggingClassWriter.java

byte[] b = this.strategy.generate(this);

public byte[] generate(ClassGenerator cg) throws Exception {
        ClassWriter cw = this.getClassWriter();
        this.transform(cg).generateClass(cw);
        return this.transform(cw.toByteArray());
    }

其中getClassWriter()

protected ClassWriter getClassWriter() throws Exception {
     return new DebuggingClassWriter(true);
}

DebuggingClassWriter重写了toByteArray()方法,调用父类ClassWriter的toByteArray()方法生成字节

public byte[] toByteArray() {
        return (byte[])AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                byte[] b = DebuggingClassWriter.super.toByteArray();
                if (DebuggingClassWriter.debugLocation != null) {
                    String dirs = DebuggingClassWriter.this.className.replace('.', File.separatorChar);

                    try {
                        (new File(DebuggingClassWriter.debugLocation + File.separatorChar + dirs)).getParentFile().mkdirs();
                        File file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".class");
                        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));

                        try {
                            out.write(b);
                        } finally {
                            out.close();
                        }
                        // asm技术生成class文件
                        if (DebuggingClassWriter.traceEnabled) {
                            file = new File(new File(DebuggingClassWriter.debugLocation), dirs + ".asm");
                            out = new BufferedOutputStream(new FileOutputStream(file));

                            try {
                                ClassReader cr = new ClassReader(b);
                                PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
                                TraceClassVisitor tcv = new TraceClassVisitor((ClassVisitor)null, pw);
                                cr.accept(tcv, false);
                                pw.flush();
                            } finally {
                                out.close();
                            }
                        }
                    } catch (IOException var17) {
                        throw new CodeGenerationException(var17);
                    }
                }

                return b;
            }
        });
    }

首先看DebuggingClassWriter.debugLocation,默认null,可以设置路径,只有不为null时才会在本地生成class文件

private static String debugLocation = System.getProperty("cglib.debugLocation");

asm框架生成class文件
首先 DebuggingClassWriter有个静态代码块,除了打印日志显示代理类class文件生成目录外,还判断cglib包下的是否存在TraceClassVisitor类(注意jdk下有一个一样的类),存在的的话赋值traceEnabled = true,然后会用asm技术去生成class文件

static {
    if (debugLocation != null) {
        System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");

        try {
            Class.forName("net.sf.cglib.asm.util.TraceClassVisitor");
            traceEnabled = true;
        } catch (Throwable var1) {
            ;
        }
    }
}

** 回到Enhancer实例化代理类对象**
直接看this.firstInstance(gen)怎么实例化

protected Object firstInstance(Class type) throws Exception {
   return this.classOnly ? type : this.createUsingReflection(type);
}

private Object createUsingReflection(Class type) {
    setThreadCallbacks(type, this.callbacks);

    Object var2;
    try {
        //参数类型为空的实例化方法,这里指的是代理类的构造方法参数
        if (this.argumentTypes == null) {
            var2 = ReflectUtils.newInstance(type);
            return var2;
        }
        // 参数不为空的实例化方法
        var2 = ReflectUtils.newInstance(type, this.argumentTypes, this.arguments);
    } finally {
        setThreadCallbacks(type, (Callback[])null);
    }

    return var2;
}

我们创建代理类对象时有两种方法
create()就表示代理类用默认的构造函数实例化对象
create(Class[] argumentTypes, Object[] arguments)就表示代理类用有参的构造函数实例化对象

最后会调用ReflectUtils.newInstance(Constructor cstruct, Object[] args)实例化代理类对象

public static Object newInstance(Constructor cstruct, Object[] args) {
    boolean flag = cstruct.isAccessible();

    Object var4;
    try {
        cstruct.setAccessible(true);
        Object result = cstruct.newInstance(args);
        var4 = result;
    } catch (InstantiationException var10) {
        throw new CodeGenerationException(var10);
    } catch (IllegalAccessException var11) {
        throw new CodeGenerationException(var11);
    } catch (InvocationTargetException var12) {
        throw new CodeGenerationException(var12.getTargetException());
    } finally {
        cstruct.setAccessible(flag);
    }

    return var4;
}

CGLIB生成的字节码文件

//该设置用于输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\class");

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.yirendai.borrowbase.node.service.impl;

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 ConcreteSubject$$EnhancerByCGLIB$$6e76667 extends ConcreteSubject 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$request$0$Method;
    private static final MethodProxy CGLIB$request$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 var0 = Class.forName("com.yirendai.borrowbase.node.service.impl.ConcreteSubject$$EnhancerByCGLIB$$6e76667");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$finalize$1$Method = var10000[0];
        CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
        CGLIB$equals$2$Method = var10000[1];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[2];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[3];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[4];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        CGLIB$request$0$Method = ReflectUtils.findMethods(new String[]{"request", "()V"}, (var1 = Class.forName("com.yirendai.borrowbase.node.service.impl.ConcreteSubject")).getDeclaredMethods())[0];
        CGLIB$request$0$Proxy = MethodProxy.create(var1, var0, "()V", "request", "CGLIB$request$0");
    }

    final void CGLIB$request$0() {
        super.request();
    }

    public final void request() {
        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$request$0$Method, CGLIB$emptyArgs, CGLIB$request$0$Proxy);
        } else {
            super.request();
        }
    }

    final void CGLIB$finalize$1() throws Throwable {
        super.finalize();
    }

    protected final void finalize() throws Throwable {
        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$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
        } else {
            super.finalize();
        }
    }

    final boolean CGLIB$equals$2(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$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$3() {
        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$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$4() {
        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$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$5() 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$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -1574182249:
            if (var10000.equals("finalize()V")) {
                return CGLIB$finalize$1$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$5$Proxy;
            }
            break;
        case 37055110:
            if (var10000.equals("request()V")) {
                return CGLIB$request$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$2$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$3$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$4$Proxy;
            }
        }

        return null;
    }

    public ConcreteSubject$$EnhancerByCGLIB$$6e76667() {
        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) {
        ConcreteSubject$$EnhancerByCGLIB$$6e76667 var1 = (ConcreteSubject$$EnhancerByCGLIB$$6e76667)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);
        ConcreteSubject$$EnhancerByCGLIB$$6e76667 var10000 = new ConcreteSubject$$EnhancerByCGLIB$$6e76667();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        ConcreteSubject$$EnhancerByCGLIB$$6e76667 var10000 = new ConcreteSubject$$EnhancerByCGLIB$$6e76667();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        ConcreteSubject$$EnhancerByCGLIB$$6e76667 var10000 = new ConcreteSubject$$EnhancerByCGLIB$$6e76667;
        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();
    }
}

  • 生成的代理类ConcreteSubject$$EnhancerByCGLIB$$6e76667继承被代理类ConcreteSubject,所以委托类不能被final修饰。同样委托类存在final修饰的方法,那么该方法也不能被代理。
  • 代理类会为委托方法生成两个方法,一个是重写request方法,另一个是CGLIB$request$0方法,我们可以看到它是直接调用父类的request方法。
  • 当执行代理对象的request方法是,会首先判断一下是否存在实现了MethodInterceptor接口的CGLIB$CALLBACK_0,如果存在,则将调用MethodInterceptor中的intercept方法。

从中我们看到,该类ConcreteSubject$$EnhancerByCGLIB$$6e76667继承自ConcreteSubject,实现了接口factory。并且在其中我们看到不仅是父类ConcreteSubject中的方法request在其中被重写了之外,ConcreteSubject的父类同样会被重写。足以见得,cglib利用继承的方式动态创建了被代理类的子类,通过ASM生成父类中所有public非final修饰的方法,实现了代理。

代理类的FastClass

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.yirendai.borrowbase.node.service.impl;

import com.yirendai.borrowbase.node.service.impl.ConcreteSubject..EnhancerByCGLIB..6e76667;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;

public class ConcreteSubject$$EnhancerByCGLIB$$6e76667$$FastClassByCGLIB$$e4ed01f9 extends FastClass {
    public ConcreteSubject$$EnhancerByCGLIB$$6e76667$$FastClassByCGLIB$$e4ed01f9(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -2055565910:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 13;
            }
            break;
        case -1725733088:
            if (var10000.equals("getClass()Ljava/lang/Class;")) {
                return 24;
            }
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                return 20;
            }
            break;
        case -1411812934:
            if (var10000.equals("CGLIB$hashCode$4()I")) {
                return 15;
            }
            break;
        case -1026001249:
            if (var10000.equals("wait(JI)V")) {
                return 22;
            }
            break;
        case -894172689:
            if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 4;
            }
            break;
        case -623122092:
            if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
                return 11;
            }
            break;
        case -419626537:
            if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 8;
            }
            break;
        case 37055110:
            if (var10000.equals("request()V")) {
                return 6;
            }
            break;
        case 243996900:
            if (var10000.equals("wait(J)V")) {
                return 23;
            }
            break;
        case 374345669:
            if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) {
                return 14;
            }
            break;
        case 560567118:
            if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
                return 7;
            }
            break;
        case 811063227:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 3;
            }
            break;
        case 946854621:
            if (var10000.equals("notifyAll()V")) {
                return 26;
            }
            break;
        case 973717575:
            if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
                return 10;
            }
            break;
        case 1116248544:
            if (var10000.equals("wait()V")) {
                return 21;
            }
            break;
        case 1221173700:
            if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 5;
            }
            break;
        case 1230699260:
            if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
                return 9;
            }
            break;
        case 1365077639:
            if (var10000.equals("CGLIB$finalize$1()V")) {
                return 18;
            }
            break;
        case 1517819849:
            if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) {
                return 19;
            }
            break;
        case 1584330438:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 12;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 0;
            }
            break;
        case 1902039948:
            if (var10000.equals("notify()V")) {
                return 25;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 1;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 2;
            }
            break;
        case 2011844968:
            if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) {
                return 16;
            }
            break;
        case 2014567037:
            if (var10000.equals("CGLIB$request$0()V")) {
                return 17;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -2083498450:
            if (var1.equals("CGLIB$finalize$1")) {
                switch(var2.length) {
                case 0:
                    return 18;
                }
            }
            break;
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 1;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 0;
                    }
                }
            }
            break;
        case -1053468136:
            if (var1.equals("getCallbacks")) {
                switch(var2.length) {
                case 0:
                    return 10;
                }
            }
            break;
        case -1039689911:
            if (var1.equals("notify")) {
                switch(var2.length) {
                case 0:
                    return 25;
                }
            }
            break;
        case -124978608:
            if (var1.equals("CGLIB$equals$2")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 14;
                    }
                }
            }
            break;
        case -60403779:
            if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 12;
                    }
                }
            }
            break;
        case -29025554:
            if (var1.equals("CGLIB$hashCode$4")) {
                switch(var2.length) {
                case 0:
                    return 15;
                }
            }
            break;
        case 3641717:
            if (var1.equals("wait")) {
                switch(var2.length) {
                case 0:
                    return 21;
                case 1:
                    if (var2[0].getName().equals("long")) {
                        return 23;
                    }
                    break;
                case 2:
                    if (var2[0].getName().equals("long") && var2[1].getName().equals("int")) {
                        return 22;
                    }
                }
            }
            break;
        case 85179481:
            if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 13;
                    }
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        case 161998109:
            if (var1.equals("CGLIB$STATICHOOK1")) {
                switch(var2.length) {
                case 0:
                    return 20;
                }
            }
            break;
        case 270818808:
            if (var1.equals("CGLIB$request$0")) {
                switch(var2.length) {
                case 0:
                    return 17;
                }
            }
            break;
        case 495524492:
            if (var1.equals("setCallbacks")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 8;
                    }
                }
            }
            break;
        case 1095692943:
            if (var1.equals("request")) {
                switch(var2.length) {
                case 0:
                    return 6;
                }
            }
            break;
        case 1154623345:
            if (var1.equals("CGLIB$findMethodProxy")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
                        return 11;
                    }
                }
            }
            break;
        case 1543336190:
            if (var1.equals("CGLIB$toString$3")) {
                switch(var2.length) {
                case 0:
                    return 19;
                }
            }
            break;
        case 1811874389:
            if (var1.equals("newInstance")) {
                switch(var2.length) {
                case 1:
                    String var10001 = var2[0].getName();
                    switch(var10001.hashCode()) {
                    case -845341380:
                        if (var10001.equals("net.sf.cglib.proxy.Callback")) {
                            return 4;
                        }
                        break;
                    case 1730110032:
                        if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
                            return 5;
                        }
                    }
                case 2:
                default:
                    break;
                case 3:
                    if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 3;
                    }
                }
            }
            break;
        case 1817099975:
            if (var1.equals("setCallback")) {
                switch(var2.length) {
                case 2:
                    if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
                        return 7;
                    }
                }
            }
            break;
        case 1902066072:
            if (var1.equals("notifyAll")) {
                switch(var2.length) {
                case 0:
                    return 26;
                }
            }
            break;
        case 1905679803:
            if (var1.equals("getCallback")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("int")) {
                        return 9;
                    }
                }
            }
            break;
        case 1950568386:
            if (var1.equals("getClass")) {
                switch(var2.length) {
                case 0:
                    return 24;
                }
            }
            break;
        case 1951977611:
            if (var1.equals("CGLIB$clone$5")) {
                switch(var2.length) {
                case 0:
                    return 16;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        6e76667 var10000 = (6e76667)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.request();
                return null;
            case 7:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                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:
                return 6e76667.CGLIB$findMethodProxy((Signature)var3[0]);
            case 12:
                6e76667.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 13:
                6e76667.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 14:
                return new Boolean(var10000.CGLIB$equals$2(var3[0]));
            case 15:
                return new Integer(var10000.CGLIB$hashCode$4());
            case 16:
                return var10000.CGLIB$clone$5();
            case 17:
                var10000.CGLIB$request$0();
                return null;
            case 18:
                var10000.CGLIB$finalize$1();
                return null;
            case 19:
                return var10000.CGLIB$toString$3();
            case 20:
                6e76667.CGLIB$STATICHOOK1();
                return null;
            case 21:
                var10000.wait();
                return null;
            case 22:
                var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
                return null;
            case 23:
                var10000.wait(((Number)var3[0]).longValue());
                return null;
            case 24:
                return var10000.getClass();
            case 25:
                var10000.notify();
                return null;
            case 26:
                var10000.notifyAll();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        6e76667 var10000 = new 6e76667;
        6e76667 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 26;
    }
}

被代理类的FastClass

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.yirendai.borrowbase.node.service.impl;

import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class ConcreteSubject$$FastClassByCGLIB$$77e9e756 extends FastClass {
    public ConcreteSubject$$FastClassByCGLIB$$77e9e756(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1725733088:
            if (var10000.equals("getClass()Ljava/lang/Class;")) {
                return 7;
            }
            break;
        case -1026001249:
            if (var10000.equals("wait(JI)V")) {
                return 2;
            }
            break;
        case 37055110:
            if (var10000.equals("request()V")) {
                return 0;
            }
            break;
        case 243996900:
            if (var10000.equals("wait(J)V")) {
                return 3;
            }
            break;
        case 946854621:
            if (var10000.equals("notifyAll()V")) {
                return 9;
            }
            break;
        case 1116248544:
            if (var10000.equals("wait()V")) {
                return 1;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 4;
            }
            break;
        case 1902039948:
            if (var10000.equals("notify()V")) {
                return 8;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 5;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 6;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 5;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 4;
                    }
                }
            }
            break;
        case -1039689911:
            if (var1.equals("notify")) {
                switch(var2.length) {
                case 0:
                    return 8;
                }
            }
            break;
        case 3641717:
            if (var1.equals("wait")) {
                switch(var2.length) {
                case 0:
                    return 1;
                case 1:
                    if (var2[0].getName().equals("long")) {
                        return 3;
                    }
                    break;
                case 2:
                    if (var2[0].getName().equals("long") && var2[1].getName().equals("int")) {
                        return 2;
                    }
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 6;
                }
            }
            break;
        case 1095692943:
            if (var1.equals("request")) {
                switch(var2.length) {
                case 0:
                    return 0;
                }
            }
            break;
        case 1902066072:
            if (var1.equals("notifyAll")) {
                switch(var2.length) {
                case 0:
                    return 9;
                }
            }
            break;
        case 1950568386:
            if (var1.equals("getClass")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        ConcreteSubject var10000 = (ConcreteSubject)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.request();
                return null;
            case 1:
                var10000.wait();
                return null;
            case 2:
                var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
                return null;
            case 3:
                var10000.wait(((Number)var3[0]).longValue());
                return null;
            case 4:
                return new Boolean(var10000.equals(var3[0]));
            case 5:
                return var10000.toString();
            case 6:
                return new Integer(var10000.hashCode());
            case 7:
                return var10000.getClass();
            case 8:
                var10000.notify();
                return null;
            case 9:
                var10000.notifyAll();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        ConcreteSubject var10000 = new ConcreteSubject;
        ConcreteSubject var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 9;
    }
}

我们来看生成代理类的request方法

public final void request() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            //执行自定义拦截器
            //private static final Method CGLIB$request$0$Method;
            //private static final MethodProxy CGLIB$request$0$Proxy;
           //代理类中Method为被代理对象方法,MethodProxy为代理的方法,可以看到是一 一对应的
            var10000.intercept(this, CGLIB$request$0$Method, CGLIB$emptyArgs, CGLIB$request$0$Proxy);
        } else {
            super.request();
        }
    }

执行自定义拦截器

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行方法前dosomething。。。");
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("执行方法后dosomething。。。");
        return invoke;
    }

methodProxy.invokeSuper(o, objects)指的是MethodProxy.invokeSuper

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        //  f2代理类FastClass
        return this.f2.invoke(this.i2, obj, args);
    } catch (InvocationTargetException var4) {
        throw var4.getTargetException();
    }
}

这里的f2通过代理对象生成的,是在静态代码块中执行MethodProxy.create传递进来的

// c1被代理对象,c2代理对象
public static MethodProxy create(ClassLoader loader, Class c1, Class c2, String desc, String name1, String name2) {
    final Signature sig1 = new Signature(name1, desc);
    Signature sig2 = new Signature(name2, desc);
    // 被代理类FastClass
    FastClass f1 = helper(loader, c1);
    // 代理类FastClass
    FastClass f2 = helper(loader, c2);
    // 被代理类的方法签名(index)
    int i1 = f1.getIndex(sig1);
    // 代理类的方法签名(index)
    int i2 = f2.getIndex(sig2);
    MethodProxy proxy;
    if (i1 < 0) {
        proxy = new MethodProxy() {
            public Object invoke(Object obj, Object[] args) throws Throwable {
                throw new IllegalArgumentException("Protected method: " + sig1);
            }
        };
    } else {
        proxy = new MethodProxy();
    }

    proxy.f1 = f1;
    proxy.f2 = f2;
    proxy.i1 = i1;
    proxy.i2 = i2;
    proxy.sig = sig1;
    proxy.superName = name2;
    return proxy;
}

this.f2.invoke(this.i2, obj, args);,执行的就是代理类的FastClass.invok
根据方法签名(index)快速找到代理类的方法

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        6e76667 var10000 = (6e76667)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.request();
                return null;
            case 7:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                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:
                return 6e76667.CGLIB$findMethodProxy((Signature)var3[0]);
            case 12:
                6e76667.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 13:
                6e76667.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 14:
                return new Boolean(var10000.CGLIB$equals$2(var3[0]));
            case 15:
                return new Integer(var10000.CGLIB$hashCode$4());
            case 16:
                return var10000.CGLIB$clone$5();
            case 17:
                var10000.CGLIB$request$0();
                return null;
            case 18:
                var10000.CGLIB$finalize$1();
                return null;
            case 19:
                return var10000.CGLIB$toString$3();
            case 20:
                6e76667.CGLIB$STATICHOOK1();
                return null;
            case 21:
                var10000.wait();
                return null;
            case 22:
                var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
                return null;
            case 23:
                var10000.wait(((Number)var3[0]).longValue());
                return null;
            case 24:
                return var10000.getClass();
            case 25:
                var10000.notify();
                return null;
            case 26:
                var10000.notifyAll();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

执行代理类的CGLIB$request$0()方法,最终执行被代理的request方法

  final void CGLIB$request$0() {
        super.request();
    }

可以看到cglib是直接继承了原有类,实现了Factory接口,而jdk是实现了自己的顶层接口,继承了Proxy接口。这里需要注意一下,这样的话,按照类来找话,jdk就找不到他的实现了,因为他的实现类实际上是一个Proxy类,而不是他自己。

Spring中使用的是哪种代理呢?

先上结论,如果一个类有顶层接口,则默认使用jdk的动态代理来代理,如果直接是一个类,则使用cglib动态代理。 其次,如果没有需要代理的方法,如所有方法都没有@Transactional注解,Aop这种,则不会被代理。
问题来了,只说结论,没有依据,怎么让人信服?

@Service
public class TestServiceImpl implements TestService {
    @Transactional
    public void updateActual() {
        
    }

}

在这里,我们实现一个Service,让他实现一个顶层接口,然后我们如果在Controller里使用
@Autowired
private TestServiceImpl testServiceImpl;
注解来注入,这时候会发现,启动时报错的。
报错也很明显:

The bean 'testServiceImpl' could not be injected as a 'com.rrc.finance.service.apply.TestServiceImpl' because it is a JDK dynamic proxy that implements:
    com.rrc.finance.service.apply.TestService

改成 :@Autowired private TestService testServiceImpl; 即可正常启动。证明动态代理生成的代码是一个 TestService 却不是一个TestServiceImpl。使用的是jdk的动态代理。这里去掉事务注解和 去掉接口实现 自己可以再试一下。

参考:https://www.jianshu.com/p/9cdcf4e5c27d
https://blog.csdn.net/lovejj1994/article/details/78080124
https://zhuanlan.zhihu.com/p/92019070
https://www.jianshu.com/p/c42b3feecb09
https://blog.csdn.net/yu_kang/article/details/88530016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容