coding……
但行好事 莫问前程

彻底搞懂动态代理

生活中我们肯定知道代理商的概念,代理商代替厂家售卖其生产的商品,厂家“委托”代理商为其销售商品。通过代理商这种销售模式,普通消费者是不直接跟厂家打交道,但是却能获得厂家的商品服务,也就是说,“委托者”对普通消费者来说是不可见的。其次,同一厂家的不同代理商,可以针对自身的情况做一些个性化的营销策略,消费者通过代理商获取不同的服务,但代理商并没有改变厂家的任何策略。我们把代理商和厂家进行抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。而这种委托类——代理类的模式,就是代理模式。使用代理,有如下好处:

  • 隐藏委托类的实现
  • 实现使用方与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理(加强委托类的功能)

代理模式有两种实现,分别是静态代理和动态代理。对于静态代理,因为非常简单,下面不做太多介绍。对于动态代理,下面会分别介绍一下JDK动态代理和CGLIB动态代理的使用及原理。

1. 概念

1.1 什么是代理?

代理是一种常用的设计模式,其目的就是为其委托方对象提供一个代理对象,使用代理对象控制对源对象的引用。代理类负责为委托类预处理消息并转发消息,以及进行消息被委托类执行后的后续处理,说的通俗一点就是,通过代理模式可以在步修改委托类的前提下,完成对委托类方法的“功能加强”。

为了保持行为的一致性,代理类和委托类通常会实现相同的接口或者继承代理类,所以在访问者看来两者没有丝毫的区别。通过代理类这中间层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

2. 静态代理

若代理类在程序运行前就已经存在,那么这种代理方式被称为静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。下面我们用RealSubject类表示委托类,Proxy类表示代理类,来介绍一下静态代理的实现,委托类和代理类都实现了Subject接口,代理类持有委托类的实例,并在代理类中对委托类及逆行额外的处理。Subject接口的定义如下:

public interface Subject {
    void eat();
}

RealSubject类定义如下:

public class RealSubject implements Subject{
    @Override
    public void eat() {
        System.out.println("吃饭");
    }
}

代理类Proxy定义如下:

public class Proxy implements Subject {

    private Subject subject;

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

    @Override
    public void eat() {
        System.out.println("先洗手");
        subject.eat();
    }
}

使用实例:

public static void main(String[] args) {
    Subject subject = new Proxy(new RealSubject());
    subject.eat();
}

从代理类Proxy可以看出,静态代理代理类和委托类都实现同一接口,代理类中持有一个委托类的实例成员变量,在代理类实现Subject接口中的方法时,调用委托类的方法,并对方法进行一些个性化的改动,比如上面Proxy类就通过代理实现了“饭前洗手”。但是静态代理存在明显的问题:

  • 委托类和代理类必须实现所有Subject接口中所有的方法,如果接口修改,所有委托类和代理类必须同步修改
  • 一个委托类对应一个代理类,如果委托类比较多,相应就要有很多代理类,代码将非常臃肿

3. 动态代理

代理类在程序运行时创建的代理方式被称为动态代理。 这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

Java中动态代理有两种实现方式,分别时JDK动态代理和CGLIB动态代理。这两种动态代理方式,有着不同的使用场景,这里先讲一下结论——JDK动态代理至适用于委托类实现了接口的情况,如果委托类没有实现接口,那么只能使用CGLIB动态代理,后面原理分析中会揭晓原因。

3.1 JDK动态代理

3.1.1 简介

JDK动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

  • InvocationHandler
public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

该接口中仅定义了一个方法,该方法用于定义代理类对委托类方法的代理逻辑。在实际使用时,第一个参数proxy是指代理类对象,method是被代理的方法,args为该方法的参数数组。该方法在生成的代理类中被使用。

  • Proxy

该类即为动态代理类,其中主要包含以下内容:

protected Proxy(InvocationHandler h) {
    Objects.requireNonNull(h);
    this.h = h;
}

构造函数,用于给内部的InvocationHandler h赋值。Proxy类中还有一个比较重要的方法newProxyInstance:

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

该方法用于返回代理类的一个实例,返回后的代理类对象可以当作委托类对象使用(因为代理类跟委托类一样,也实现了Subject接口,所以代理类对象可调用委托类的在Subject接口中声明过的方法)。

所谓JDK动态代理就是动态生成这样一种class:在运行时才真正生成,在生成它时你必须提供一组interface给它,动态生成的代理类会实现这些 interface。你可以把动态代理类实例当作这些interface中的任何一个实例来用。当然,这个动态代理对象其实就是一个代理,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它完成代理逻辑实现。所以使用动态代理类时,必须实现InvocationHandler接口。

3.1.2 JDK动态代理的使用

JDK动态代理可以通过如下步骤使用:

  1. 创建接口Subject及委托类RealSubject(实现了Subject接口)
  2. 创建一个实现InvocationHandler接口的类,实现invoke方法
  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理对象
  4. 使用代理对象调用方法
  • 定义一个Subject接口和委托类RealSubject
public interface Subject {
    String SayHello(String name);

    String SayGoodBye();
}
public class RealSubject implements Subject {
    @Override
    public String SayHello(String name) {
        return "hello " + name;
    }

    @Override
    public String SayGoodBye() {
        return "good bye!";
    }
}
  • 创建一个实现InvocationHandler接口的类
public class DynamicProxy implements InvocationHandler {

    private Object object;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在代理方法执行前添加一些自己的操作
        System.out.print("在调用之前,打印方法名称:");
        System.out.println("Method:" + method);

        //委托类方法执行
        Object obj = method.invoke(object, args);

        //在代理方法执行后添加一些自己的操作
        System.out.println("方法执行结束");

        return obj;
    }

    public DynamicProxy(Object object) {
        this.object = object;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(
                object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                this

        );
    }
}

实现的invoke方法,其实就是代理方法的执行逻辑。我们这invoke方法中对于委托类方法进行了“加强”,在委托类方法执行前打印方法名称,在委托类方法执行结束,打印一段文字”good bye!”。另外我们可以看到,委托类方法的执行是通过反射完成的,就是invoke方法中的method.invoke(object, args)。

这里我们再添加一个工厂类,来获取代理对象:

public class SubjectProxyFactory {
    public static Subject newJdkProxy() {
        //代理RealSubject
        DynamicProxy dynamicProxy = new DynamicProxy(new RealSubject());
        return dynamicProxy.getProxy();
    }
}
  • 测试代理功能
public static void main(String[] args) {
    //获取代理对象
    Subject subject = SubjectProxyFactory.newJdkProxy();

    System.out.println("动态代理对象的类型:" + subject.getClass().getName());

    String hello = subject.SayHello("zhuoli");
    System.out.println(hello);
    System.out.println("-------------------------");
    String goodbye = subject.SayGoodBye();
    System.out.println(goodbye);
}

输出结果:

动态代理对象的类型:com.sun.proxy.$Proxy0
在调用之前,打印方法名称:Method:public abstract java.lang.String com.zhuoli.service.thinking.java.proxy.jdkproxy.Subject.SayHello(java.lang.String)
方法执行结束
hello zhuoli
-------------------------
在调用之前,打印方法名称:Method:public abstract java.lang.String com.zhuoli.service.thinking.java.proxy.jdkproxy.Subject.SayGoodBye()
方法执行结束
good bye!

可以看到,通过Proxy的静态方法newProxyInstance得到的是一个代理对象类型,即打印结果的com.sun.proxy.$Proxy0。另外委托类RealSubject的sayHello方法和sayGoodBye方法都得到了功能增强,也就是讲JDK动态代理生效了。

一般讲到这,动态代理的使用就可以结束了,但是我们有没有想过JDK动态代理的原理是什么,为什么实现了InvocationHandler接口,可以指定代理方法的逻辑?代理类是怎么来的?为什么调用代理类的方法时,会去执行代理对象关联的handler对象的invoke方法?带着这些问题,我们来看一下源码。

3.1.3 JDK动态代理实现分析

从上面JDK动态代理的使用我们可以知道,JDK动态代理的入口就在动态代理对象的生成上,调用代理类对象方法就能执行handler的invoke方法,肯定跟代理类生成有关,下面就来看一下源码。

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

    /*
     * 查找或生成委托类的代理类Class对象
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * 使用指定的InvocationHandler调用其构造函数,生成代理对象
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        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);
    }
}

跟进去看一下代理类Class对象如何生成的,getProxyClass0:

//生成代理类Class对象
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    //如果存在实现了interfaces接口,被类加载器loader定义的Class对象,
    //则直接从缓存中获取返回,否则通过ProxyClassFactory创建代理类
    return proxyClassCache.get(loader, interfaces);
}

看一下proxyClassCache定义:

/**
 * a cache of proxy classes
 */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

就是一个代理Class类对象的缓存,继续跟进proxyClassCache.get方法:

public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

可以看到它调用了supplier.get()获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。来看一下supplier的get方法做了什么:

public synchronized V get() { // serialize access
    // re-check
    Supplier<V> supplier = valuesMap.get(subKey);
    if (supplier != this) {
        // something changed while we were waiting:
        // might be that we were replaced by a CacheValue
        // or were removed because of failure ->
        // return null to signal WeakCache.get() to retry
        // the loop
        return null;
    }
    // else still us (supplier == this)

    // create new value
    V value = null;
    try {
        value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    } finally {
        if (value == null) { // remove us on failure
            valuesMap.remove(subKey, this);
        }
    }
    // the only path to reach here is with non-null value
    assert value != null;

    // wrap value with CacheValue (WeakReference)
    CacheValue<V> cacheValue = new CacheValue<>(value);

    // put into reverseMap
    reverseMap.put(cacheValue, Boolean.TRUE);

    // try replacing us with CacheValue (this should always succeed)
    if (!valuesMap.replace(subKey, this, cacheValue)) {
        throw new AssertionError("Should not reach here");
    }

    // successfully replaced us with new CacheValue -> return the value
    // wrapped by it
    return value;
}

可以看到该方法是返回值value是调用了valueFactory.apply(key, parameter)方法返回的,其中valueFactory是ProxyClassFactory实例,继续跟进去看一下:

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    for (Class<?> intf : interfaces) {
        /*
         * Verify that the class loader resolves the name of this
         * interface to the same Class object.
         */
        Class<?> interfaceClass = null;
        try {
            interfaceClass = Class.forName(intf.getName(), false, loader);
        } catch (ClassNotFoundException e) {
        }
        if (interfaceClass != intf) {
            throw new IllegalArgumentException(
                intf + " is not visible from class loader");
        }
        /*
         * Verify that the Class object actually represents an
         * interface.
         */
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException(
                interfaceClass.getName() + " is not an interface");
        }
        /*
         * Verify that this interface is not a duplicate.
         */
        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
            throw new IllegalArgumentException(
                "repeated interface: " + interfaceClass.getName());
        }
    }

    String proxyPkg = null;     // package to define proxy class in
    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

    /*
     * Record the package of a non-public proxy interface so that the
     * proxy class will be defined in the same package.  Verify that
     * all non-public proxy interfaces are in the same package.
     */
    for (Class<?> intf : interfaces) {
        int flags = intf.getModifiers();
        if (!Modifier.isPublic(flags)) {
            accessFlags = Modifier.FINAL;
            String name = intf.getName();
            int n = name.lastIndexOf('.');
            String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
            if (proxyPkg == null) {
                proxyPkg = pkg;
            } else if (!pkg.equals(proxyPkg)) {
                throw new IllegalArgumentException(
                    "non-public interfaces from different packages");
            }
        }
    }

    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }

    /*
     * Choose a name for the proxy class to generate.
     */
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    /*
     * Generate the specified proxy class.
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        /*
         * A ClassFormatError here means that (barring bugs in the
         * proxy class generation code) there was some other
         * invalid aspect of the arguments supplied to the proxy
         * class creation (such as virtual machine limitations
         * exceeded).
         */
        throw new IllegalArgumentException(e.toString());
    }
}

到这里,可以看到代理类字节码生成的逻辑:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

我们使用ProxyGenerator.generateProxyClass测试一下这个方法生成的字节码是个什么样子:

public static void main(String[] args) {
    createProxyClassFile();
}

private static void createProxyClassFile() {
    String name = "ProxySubject";
    byte[] data = ProxyGenerator.generateProxyClass(name, new Class[]{Subject.class});
    FileOutputStream out = null;
    try {
        out = new FileOutputStream("D:\\" + name + ".class");
        out.write(data);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (null != out) try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

反编译D盘下生成的ProxySubject.class文件,如下:

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

    public ProxySubject(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 SayGoodBye() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String SayHello(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m4, 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 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"));
            m3 = Class.forName("com.zhuoli.service.thinking.java.proxy.jdkproxy.Subject").getMethod("SayGoodBye");
            m4 = Class.forName("com.zhuoli.service.thinking.java.proxy.jdkproxy.Subject").getMethod("SayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

这就是委托类生成的代理类,它继承自Proxy并实现了我们定义的Subject接口。也就是说我们通过Proxy.newInstance方法获取的代理类实例对象其实就是上述生成的类的实例对象。

Proxy类中有一个InvocationHandler成员变量h,我们在上述newProxyInstance方法中传入,在上面的代码分析中,拿到代理类Class类对象后,通过反射调用了代理类的构造方法,如下:

cons.newInstance(new Object[]{h})

也就是说,我们自定义的InvocationHandler对象通过这个构造函数传给代理类了,初始化了代理类的InvocationHandler成员变量(继承自Proxy类)。

如果我们调用代理类的sayHello方法,实际调用的是如下方法:

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

也就是讲,我们执行的是自定义InvocationHandler对象的invoke方法,m4是委托类的sayHello方法,如下:

m4 = Class.forName("com.zhuoli.service.thinking.java.proxy.jdkproxy.Subject").getMethod("SayHello", Class.forName("java.lang.String"));

在自定义InvocationHandler的invoke方法中,我们定义了代理方法的逻辑,就是在这里生效的。回到我们之前的问题,为什么调用代理类对象的sayHello方法,执行的实际是自定义InvocationHandler的invoke方法?

因为JDK动态代理最终生成的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,调用了自定义InvocationHandler对象的invoke方法,在自定义InvocationHandler的invoke方法内部,我们通过反射执行了委托类的方法

3.2 CGLIB动态代理

3.2.1 简介

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB动态代理要基于以下两个包:

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.12</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>7.1</version>
</dependency>

如果使用Spring,就不用显式引入上述两个包,因为Spring内部自己实现了CGLIB,相关的类在org.springframework.cglib.proxy包下。我们这里不使用Spring的CGLIB。

CGLIB动态代理类位于net.sf.cglib.proxy包下,一般主要涉及到以下两个类:

  • MethodInterceptor
public interface MethodInterceptor extends Callback {
    Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}

该接口中仅定义了一个方法,该方法用于定义代理类对委托类方法的代理逻辑。在实际使用时,第一个参数var1是指代理类对象,第二个参数var2是指委托类中被代理的方法,第三个参数var3为该方法的参数数组,最后一个参数var4是指代理类中生成的与委托类方法相同的方法对应的MethodProxy,可以用来调用委托类中的方法,跟JDK动态代理中invoke方法中的method.invoke(object, args)功能相同,但是实现原理有差别,CGLIB动态代理对委托类方法的调用不用使用反射。最后一个参数这样讲有点难以理解,下面会详细介绍。该方法在生成的代理类中被使用。

  • Enhancer

跟JDK动态代理中的Proxy功能类似,用于生成动态代理对象。这个类的成员变量比较多,使用CGLIB动态代理,我们只需要了解以下两个成员变量:

public void setSuperclass(Class superclass) {
    if (superclass != null && superclass.isInterface()) {
        this.setInterfaces(new Class[]{superclass});
    } else if (superclass != null && superclass.equals(Object.class)) {
        this.superclass = null;
    } else {
        this.superclass = superclass;
    }

}

superclass就是我们的委托类Class对象,CGLIB动态代理时基于继承实现的,就是通过这个方法指定委托类作为代理类的父类。

public void setCallback(Callback callback) {
    this.setCallbacks(new Callback[]{callback});
}

callback对象就是实现动态代理的回调对象,我们调用代理类对象的方法,就可以回调到我们自定义的MethodInterceptor的intercept方法,就是通过这个Callback对象完成的。

所谓CGLIB动态代理就是动态生成这样一种class:在运行时才真正生成,该动态生成的代理类继承了委托类。你可以把动态代理类的实例当作委托类对象来使用。当然,这个动态代理对象其实就是一个代理,它不会替你作实质性的工作,在生成它的实例时你必须提供一个interceptor,由它完成代理逻辑实现。所以使用动态代理类时,必须实现MethodInterceptor接口。

3.2.2 CGLIB动态代理的使用

CGLIB动态代理可以通过如下步骤使用:

  1. 创建委托类RealSubject
  2. 创建一个实现MethodInterceptor接口的类,实现intercept方法
  3. 创建Enhancer实例,通过setSuperclass方法来设置目标类,通过setCallback 方法来设置拦截对象,通过create方法生成Target的代理类,并返回代理类的实例
  • 定义一个委托类RealSubject
public class RealSubject {

    public String SayHello(String name) {
        return "hello " + name;
    }

    public String SayGoodBye() {
        return "good bye!";
    }
}
  • 创建一个实现MethodInterceptor接口的类
public class CGLibProxy implements MethodInterceptor {
    private static CGLibProxy instance = new CGLibProxy();

    private CGLibProxy() {
    }

    public static CGLibProxy getInstance() {
        return instance;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //在代理方法执行前添加一些自己的操作
        System.out.print("在调用之前,打印方法名称:");
        System.out.println("Method:" + method);

        //委托类方法执行
        Object obj = methodProxy.invokeSuper(o, objects);

        //在代理方法执行后添加一些自己的操作
        System.out.println("方法执行结束");

        return obj;
    }

    private Enhancer enhancer = new Enhancer();
    @SuppressWarnings("unchecked")
    public  <T> T getProxy(Class<T> clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return (T) enhancer.create();
    }
}

实现的intercept方法,其实就是代理方法的执行逻辑。我们这intercept方法中对于委托类方法进行了“加强”,在委托类方法执行前打印方法名称,在委托类方法执行结束,打印一段文字”good bye!”。另外我们可以看到,委托类方法的执行是通过methodProxy.invokeSuper完成的,这里看着像是反射,其实不是反射,下面会讲解

这里我们再添加一个工厂类,来获取代理对象:

public class RealSubjectProxyFactory {

    public static RealSubject newCglibProxy() {
        CGLibProxy cglibProxy = CGLibProxy.getInstance();
        return cglibProxy.getProxy(RealSubject.class);
    }

}
  • 测试代理功能
public static void main(String[] args) {
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\temp");

    RealSubject subject = RealSubjectProxyFactory.newCglibProxy();

    System.out.println("动态代理对象的类型:" + subject.getClass().getName());

    String hello = subject.SayHello("zhuoli");
    System.out.println(hello);
    System.out.println("-------------------------");
    String goodbye = subject.SayGoodBye();
    System.out.println(goodbye);
}

输出结果:

CGLIB debugging enabled, writing to 'D:\temp'
动态代理对象的类型:com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject$$EnhancerByCGLIB$$5532aa14
在调用之前,打印方法名称:Method:public java.lang.String com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject.SayHello(java.lang.String)
方法执行结束
hello zhuoli
-------------------------
在调用之前,打印方法名称:Method:public java.lang.String com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject.SayGoodBye()
方法执行结束
good bye!

可以看到,通过Enhancer对象的create方法得到的是一个代理对象类型,即打印结果的com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject$$EnhancerByCGLIB$$5532aa14。另外委托类RealSubject的sayHello方法和sayGoodBye方法都得到了功能增强,也就是讲JDK动态代理生效了。

测试代码中通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY的属性值来获取cglib生成的代理类,将CGLIB动态代理征程的类保存在d:\temp文件夹下。跟之前讲解JDK动态代理一样,这里我们来分析以下CGLIB动态代理的实现原理。

3.2.3 CGLIB动态代理实现分析

这里我们对CGLIB生成的字节码进行反编译,如下:

package com.zhuoli.service.thinking.java.proxy.cglibproxy;

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 RealSubject$$EnhancerByCGLIB$$5532aa14 extends RealSubject 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$SayGoodBye$0$Method;
    private static final MethodProxy CGLIB$SayGoodBye$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$SayHello$1$Method;
    private static final MethodProxy CGLIB$SayHello$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.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject$$EnhancerByCGLIB$$5532aa14");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"SayGoodBye", "()Ljava/lang/String;", "SayHello", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject")).getDeclaredMethods());
        CGLIB$SayGoodBye$0$Method = var10000[0];
        CGLIB$SayGoodBye$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "SayGoodBye", "CGLIB$SayGoodBye$0");
        CGLIB$SayHello$1$Method = var10000[1];
        CGLIB$SayHello$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "SayHello", "CGLIB$SayHello$1");
        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$2$Method = var10000[0];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[1];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[2];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[3];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    }

    final String CGLIB$SayGoodBye$0() {
        return super.SayGoodBye();
    }

	@Override
    public final String SayGoodBye() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$SayGoodBye$0$Method, CGLIB$emptyArgs, CGLIB$SayGoodBye$0$Proxy) : super.SayGoodBye();
    }

    final String CGLIB$SayHello$1(String var1) {
        return super.SayHello(var1);
    }

	@Override
    public final String SayHello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$SayHello$1$Method, new Object[]{var1}, CGLIB$SayHello$1$Proxy) : super.SayHello(var1);
    }

    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$5$Proxy;
            }
            break;
        case 1215839601:
            if (var10000.equals("SayGoodBye()Ljava/lang/String;")) {
                return CGLIB$SayGoodBye$0$Proxy;
            }
            break;
        case 1691164424:
            if (var10000.equals("SayHello(Ljava/lang/String;)Ljava/lang/String;")) {
                return CGLIB$SayHello$1$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 RealSubject$$EnhancerByCGLIB$$5532aa14() {
        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) {
        RealSubject$$EnhancerByCGLIB$$5532aa14 var1 = (RealSubject$$EnhancerByCGLIB$$5532aa14)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }
	
    static {
        CGLIB$STATICHOOK1();
    }
}

CGLIB生成的代理类同样会代理委托类中的equals,toString,hashCode,clone等方法,同样会实现Proxy接口的方法,为了清晰的展示代理类,这里把上面这些代码都清理掉了。

分析反编译后的代码可以发现,代理类(RealSubject$$EnhancerByCGLIB$$5532aa14)继承了委托类(RealSubject)并实现了Proxy接口。代理类为每个委托类的非private方法生成两个方法,以sayHello方法为例:一个是@Override的sayHello方法,一个是CGLIB$SayHello$1(CGLIB$SayHello$1相当于委托类的sayHello方法,直接调用的是super.SayHello(var1))。我们在示例代码中调用代理类对象的方法sayHello方法时,就是调用的是代理类中的sayHello方法。接下来我们着重分析代理类中的sayHello方法,看看是怎么实现的代理功能。 首先来看一下代理类的覆盖的sayHello方法:

当调用代理类的sayHello方法时,先判断MethodInterceptor成员变量是否为null,如果为null的话就调用CGLIB$BIND_CALLBACKS方法来获取拦截对象,CGLIB$BIND_CALLBACKS的反编译结果如下:

private static final void CGLIB$BIND_CALLBACKS(Object var0) {
    RealSubject$$EnhancerByCGLIB$$5532aa14 var1 = (RealSubject$$EnhancerByCGLIB$$5532aa14)var0;
    if (!var1.CGLIB$BOUND) {
        var1.CGLIB$BOUND = true;
        Object var10000 = CGLIB$THREAD_CALLBACKS.get();
        if (var10000 == null) {
            var10000 = CGLIB$STATIC_CALLBACKS;
            if (CGLIB$STATIC_CALLBACKS == null) {
                return;
            }
        }

        var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
    }

}

先从CGLIB$THREAD_CALLBACKS中get获取MethodInterceptor拦截对象,如果获取不到的话,再从CGLIB$STATIC_CALLBACKS来获取,如果也没有则认为该方法不需要代理。将获取到的MethodInterceptor对象赋值给CGLIB$CALLBACK_0成员变量。

sayHello方法执行获取MethodInterceptor拦截对象操作后,会判断MethodInterceptor是否获取到了,如果没有获取到,说明sayHello方法不需要被代理,直接调用super.sayHello调用父类(委托类)方法即可。如果获取到了,则调用MethodInterceptor拦截器对象的intercept方法,前面讲MethodInterceptor接口的intercept方法就是用来定义方法的代理逻辑的,就是在这生效的。

讲到这,CGLIB动态代理最基础的问题算是解释清楚了,那么接下来看以下另一个问题,上面讲过代理类中获取MethodInterceptor拦截对象的流程是,先从CGLIB$THREAD_CALLBACKS中获取,如果获取不到再从CGLIB$STATIC_CALLBACKS中获取,那么自定义的MethodInterceptor对象是什么时候设置到CGLIB$THREAD_CALLBACKS或者CGLIB$STATIC_CALLBACKS中的?来看源码:

//Enhancer类的create方法,创建代理类对象
public Object create() {
    this.classOnly = false;
    this.argumentTypes = null;
    //调用本类的createHelper方法
    return this.createHelper();
}

private Object createHelper() {
    this.preValidate();
    Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
    this.currentKey = key;
    //调用Enhancer父类AbstractClassGenerator的create方法创建代理对象
    Object result = super.create(key);
    return result;
}

//AbstractClassGenerator的create方法
protected Object create(Object key) {
    try {
        ClassLoader loader = this.getClassLoader();
        Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
        AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
        if (data == null) {
            Class var5 = AbstractClassGenerator.class;
            synchronized(AbstractClassGenerator.class) {
                cache = CACHE;
                data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
                if (data == null) {
                    Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
                    data = new AbstractClassGenerator.ClassLoaderData(loader);
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }

        this.key = key;
        Object obj = data.get(this, this.getUseCache());
        //该方法返回的对象是调用firstInstance方法生成的
        return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
    } catch (RuntimeException var9) {
        throw var9;
    } catch (Error var10) {
        throw var10;
    } catch (Exception var11) {
        throw new CodeGenerationException(var11);
    }
}

//AbstractClassGenerator类中的firstInstance是抽象方法,具体实现在子类Enhancer中
protected abstract Object firstInstance(Class var1) throws Exception;

//子类Enhancer的firstInstance方法
protected Object firstInstance(Class type) throws Exception {
    //调用createUsingReflection,反射代理类生成代理对象
    return this.classOnly ? type : this.createUsingReflection(type);
}

private Object createUsingReflection(Class type) {
    //反射代理类的CGLIB$SET_THREAD_CALLBACKS方法,代理类成员变量CGLIB$THREAD_CALLBACKS赋值为自定义MethodInterceptor对象callbacks
    setThreadCallbacks(type, this.callbacks);

    Object var2;
    try {
        //反射代理类,生成代理类对象
        if (this.argumentTypes != null) {
            var2 = ReflectUtils.newInstance(type, this.argumentTypes, this.arguments);
            return var2;
        }

        var2 = ReflectUtils.newInstance(type);
    } finally {
        setThreadCallbacks(type, (Callback[])null);
    }

    return var2;
}

//反射代理类的CGLIB$SET_THREAD_CALLBACKS方法
private static void setThreadCallbacks(Class type, Callback[] callbacks) {
    setCallbacksHelper(type, callbacks, "CGLIB$SET_THREAD_CALLBACKS");
}

private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
    try {
        Method setter = getCallbacksSetter(type, methodName);
        setter.invoke((Object)null, callbacks);
    } catch (NoSuchMethodException var4) {
        throw new IllegalArgumentException(type + " is not an enhanced class");
    } catch (IllegalAccessException var5) {
        throw new CodeGenerationException(var5);
    } catch (InvocationTargetException var6) {
        throw new CodeGenerationException(var6);
    }
}

从Enhancer调用create方法,到最后代理对象如何生成的逻辑都在上面这段代码中,重要节点我都加了注释,有兴趣的同学可以读一下,很简单。这里将create方法的执行步骤梳理一下:

  1. Enhancer.create()
  2. create方法调用createHelper()
  3. createHelper调用父类AbstractClassGenerator的create方法,super.create
  4. 父类AbstractClassGenerator类create方法回调Ehancer的firstInstance
  5. Enhancer类的firstInstance方法
  6. firstInstance方法调用createUsingReflection,反射代理类生成代理对象
  7. createUsingReflection中反射代理类的CGLIB$SET_THREAD_CALLBACKS方法,将代理类成员变量CGLIB$THREAD_CALLBACKS赋值为自定义MethodInterceptor对象
  8. createUsingReflection中调用ReflectUtils.newInstance,生成代理对象

可以看到自定义MethodInterceptor是在第7步设置进去的,代理类对象的生成是通过反射生成的。

现在来讲最后一个问题,我们在代理类的sayHello方法中,通过调用自定义MethodInterceptor对象的intercept实现了对委托类方法的代理逻辑,那么在intercept方法中,是如何调用委托类的sayHello方法的。我们都知道在JDK动态代理中,InvocationHandler的invoke方法对委托类方法的调用是通过反射实现的,那么在CGLIB中是如何实现的?

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    //在代理方法执行前添加一些自己的操作
    System.out.print("在调用之前,打印方法名称:");
    System.out.println("Method:" + method);

    //委托类方法执行
    Object obj = methodProxy.invokeSuper(o, objects);

    //在代理方法执行后添加一些自己的操作
    System.out.println("方法执行结束");

    return obj;
}

就是上面的methodProxy.invokeSuper,这里看着也像是反射,但其实不是。CGLIB采用了一种比反射更高效的方式,FastClass机制来实现对委托类方法的调用。FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法,下面用一个小例子来说明一下:

public class RealSubject {

    public void SayHello() {
        System.out.println("SayHello");
    }

    public void SayGoodBye() {
        System.out.println("SayGoodBye");
    }
}
public class RealSubjectFastClass {
    public Object invoke(int index, Object o, Object[] ol){
        RealSubject realSubject = (RealSubject) o;
        switch(index){
            case 1:
                realSubject.SayHello();
                return null;
            case 2:
                realSubject.SayGoodBye();
                return null;
        }
        return null;
    }

    public int getIndex(String signature){
        switch(signature.hashCode()){
            case 1535311470:
                return 1;
            case -1520982225:
                return 2;
        }
        return -1;
    }
}
public class FastClassTest {
    public static void main(String[] args){
        RealSubject realSubject = new RealSubject();
        RealSubjectFastClass realSubjectFastClass = new RealSubjectFastClass();
        int sayHelloIndex = realSubjectFastClass.getIndex("sayHello()V");
        realSubjectFastClass.invoke(sayHelloIndex, realSubject, null);

        int sayGoodByeIndex = realSubjectFastClass.getIndex("sayGoodBye()V");
        realSubjectFastClass.invoke(sayGoodByeIndex, realSubject, null);
    }
}

上例中,RealSubjectFastClass是RealSubject的Fastclass,在RealSubjectFastClass中有两个方法getIndex和invoke。在getIndex方法中对RealSubject的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。invoke根据指定的索引,调用RealSubject的方法。这样就避免了反射调用,提高了效率。CGLIB动态代理中代理类(RealSubject$$EnhancerByCGLIB$$5532aa14)中与生成Fastclass相关的代码如下:

//代理类Class对象var0
Class var0 = Class.forName("com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject$$EnhancerByCGLIB$$5532aa14");
//委托类Class对象var1
Class var1;
var1 = Class.forName("com.zhuoli.service.thinking.java.proxy.cglibproxy.RealSubject");

//委托类方法SayHello对应的MethodProxy对象
CGLIB$SayHello$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "SayHello", "CGLIB$SayHello$1");

/**
* c1: 委托类Class对象
* c2: 代理类Class对象
* desc: 委托类方法签名
* name1: 委托类方法名 SayHello
* name2: 代理类方法名 CGLIB$SayHello$1
*/
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;
}

上述MethodProxy对象在动态代理类加载的时候就创建了,这部分逻辑在动态代理类的静态代码块中。也就是讲在类加载阶段,我们为委托类的每个方法都创建了一个MethodProxy对象。那么在回过头看一下intercept方法中对委托类方法的调用逻辑,methodProxy.invokeSuper,如下:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
    	//调用init方法,初始化MethodProxy对象的fastClassInfo成员变量,fastClassInfo存储的是某个方法在委托类和代理类FastClass信息
        this.init();

        MethodProxy.FastClassInfo fci = this.fastClassInfo;

        //通过委托类FastClass对象调用invoke方法,传入的index是CGLIB$SayHello$1的index,最终调用的也是代理类的CGLIB$SayHello$1方法
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException var4) {
        throw var4.getTargetException();
    }
}

private void init() {
    if (this.fastClassInfo == null) {
        Object var1 = this.initLock;
        synchronized(this.initLock) {
        	//初始化MethodProxy对象的fastClassInfo成员变量,f1为委托类FastClass对象,f2为代理类FastClass对象
        	//i1为委托类方法签名(SayHello)index,i2为代理类方法签名(CGLIB$SayHello$1)index
            if (this.fastClassInfo == null) {
                MethodProxy.CreateInfo ci = this.createInfo;
                MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                fci.f1 = helper(ci, ci.c1);
                fci.f2 = helper(ci, ci.c2);
                fci.i1 = fci.f1.getIndex(this.sig1);
                fci.i2 = fci.f2.getIndex(this.sig2);
                this.fastClassInfo = fci;
                this.createInfo = null;
            }
        }
    }
}

从上面的分析可知invokeSuper方法实际是通过委托类FastClass对象调用invoke方法实现的,传入的index是CGLIB$SayHello$1的index,所以最终调用的也是代理类的CGLIB$SayHello$1方法,而代理类中CGLIB$SayHello$1方法实现是直接调用父类的super.sayHello,所以就实现了对委托类方法的调用。

以上就是JDK动态代理和CGLIB动态代理的全部内容,我们来总结以下两者之间的区别:

  1. JDK动态代理要求委托类必须实现接口,而CGLIB动态代理不需要。如果委托类没有实现接口,那么只能使用CGLIB动态代理。
  2. 实现机制不同,JDK动态代理生成的代理类跟委托类实现了同一个接口,而CGLIB动态代理生成的代理类继承自委托类。所以JDK动态代理只能针对接口中的方法进行代理,而CGLIB动态代理基于继承,所以只能对非final方法进行代理。
  3. 代理方法中对委托方法的调用实现机制不同,JDK动态代理是通过反射实现的,CGLIB动态代理是通过FastClass机制实现的。

最后解释一个概念,很多文章中都说JDK动态代理是基于反射实现的,而CGLIB动态代理是基于继承实现的。这句话是没问题的,但是很多人都误解了这句话的意思。JDK动态代理是基于反射实现的,意思是说代理方法对委托类方法的调用是通过反射实现的。CGLIB动态代理是基于继承实现的,意思是说CGLIB生成的代理类继承自委托类。

理论上CGLIB动态代理对委托方法的调用不用反射,效率应该更高。但是就测试结果看,这个结论不一定是完全成立的,也许是JDK的优化导致的吧。动态代理在Spring等框架中有着大量的应用,搞清楚动态代理的本质,会对我们读相关源码有很大帮助。

参考链接:

1. Java JDK 动态代理(AOP)使用及实现原理分析

2. cglib源码分析(四):cglib 动态代理原理分析

赞(4) 打赏
Zhuoli's Blog » 彻底搞懂动态代理
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

zhuoli's blog

联系我关于我

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏