Spring 动态代理时提供了 JDK 代理和 CGLIB 两种方式,一般而言,代理的目标是接口时 AOP 使用 JDK 代理来实现,CGLIB 则负责对类进行代理,两种代理方法结合使用。

一、JDK代理代码实现

package com.nineya.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface JdkTargetInterface {

    String test(String str);
}

class JdkTargetObject implements JdkTargetInterface {

    @Override
    public String test(String str) {
        System.out.println("被代理函数执行:" + str);
        return "被代理函数的返回结果";
    }
}

class JdkProxyHandler implements InvocationHandler {
    private Object target;

    public JdkProxyHandler() {
    }

    public JdkProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理函数执行:" + method);
        if (target == null) {
            return "代理函数的返回结果";
        }
        return method.invoke(target, args);
    }
}

public class JdkProxyMain {

    private static void proxyInterface() {
        // 创建代理类
        JdkTargetInterface proxyTargetInterface = (JdkTargetInterface) Proxy.newProxyInstance(
                JdkProxyMain.class.getClassLoader(), new Class[]{JdkTargetInterface.class}, new JdkProxyHandler());

        String result = proxyTargetInterface.test("这是请求参数");
        System.out.println("执行结果:" + result);
    }

    private static void proxyObject() {
        // 被代理对象
        JdkTargetObject targetObject = new JdkTargetObject();
        // 创建代理类
        JdkTargetInterface proxyTargetInterface = (JdkTargetInterface) Proxy.newProxyInstance(
                JdkProxyMain.class.getClassLoader(), new Class[]{JdkTargetInterface.class}, new JdkProxyHandler(targetObject));

        String result = proxyTargetInterface.test("这是请求参数");
        System.out.println("执行结果:" + result);
    }

    public static void main(String[] args) {
        System.out.println("## Jdk 代理接口");
        proxyInterface();
        System.out.println("## Jdk 代理对象");
        proxyObject();
    }
}

二、CGLIB代理代码实现

package com.nineya.spring.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

interface CglibTargetInterface {
    String test(String str);
}

class CglibTargetObject {

    public String test(String str) {
        System.out.println("被代理函数执行:" + str);
        return "被代理函数的返回结果";
    }
}

/**
 * cglib代理处理类
 */
class CglibProxyHandler implements MethodInterceptor {
    private Object target;

    public CglibProxyHandler() {
    }

    public CglibProxyHandler(Object target){
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理函数执行:" + method);
        if (target == null) {
            return "代理函数的返回结果";
        }
        return methodProxy.invoke(target, objects);
    }
}

public class CglibProxyMain {
    private static void proxyObject() {
        // 被代理对象
        CglibTargetObject targetObject = new CglibTargetObject();

        Enhancer enhancer = new Enhancer();
        // 被代理的类
        enhancer.setSuperclass(CglibTargetObject.class);
        // cglib代理处理类
        enhancer.setCallback(new CglibProxyHandler(targetObject));
        // 取得代理后的对象
        CglibTargetObject proxyTargetObject = (CglibTargetObject) enhancer.create();

        String result = proxyTargetObject.test("这是请求参数");
        System.out.println("执行结果:" + result);
    }
    
    private static void proxyInterface() {
        Enhancer enhancer = new Enhancer();
        // 被代理的类
        enhancer.setSuperclass(CglibTargetInterface.class);
        // cglib代理处理类
        enhancer.setCallback(new CglibProxyHandler());
        // 取得代理后的对象
        CglibTargetInterface proxyTargetObject = (CglibTargetInterface) enhancer.create();

        String result = proxyTargetObject.test("这是请求参数");
        System.out.println("执行结果:" + result);
    }
    
    public static void main(String[] args) {
        System.out.println("## CGLIB 代理接口");
        proxyInterface();
        System.out.println("## CGLIB 代理对象");
        proxyObject();
    }
}

三、对比

  1. CGLIB 需要导入第三方依赖包,JDK 代理可以直接实现。

  2. 通过观察上面两份代码可以看到,CGLIB 可以直接对接口和类进行代理,而 JDK 代理方式则只能对接口进行处理,要代理的实现类也必须要实现接口。

    JDK 代理如果对非接口类进行处理将抛出异常。

    Exception in thread "main" java.lang.IllegalArgumentException: com.nineya.spring.proxy.JdkTargetObject is not an interface
    	at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:590)
    	at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:557)
    	at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)
    	at java.lang.reflect.WeakCache.get(WeakCache.java:127)
    	at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419)
    	at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:719)
    	at com.nineya.spring.proxy.JdkProxyMain.proxyInterface(JdkProxyMain.java:43)
    	at com.nineya.spring.proxy.JdkProxyMain.main(JdkProxyMain.java:63)
    

    CGLIB 的目标类如果被 final 关键字修饰也会抛出异常,这是由于 CGLIB 通过创建目标类的子类来实现直接对目标类的代理。不直接对类进行代理的 JDK 代理方式不受影响。

    Exception in thread "main" java.lang.IllegalArgumentException: Cannot subclass final class com.nineya.spring.proxy.CglibTargetObject
    	at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:660)
    	at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358)
    	at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
    	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
    	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
    	at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
    	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
    	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
    	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
    	at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:387)
    	at com.nineya.spring.proxy.CglibProxyMain.proxyObject(CglibProxyMain.java:53)
    	at com.nineya.spring.proxy.CglibProxyMain.main(CglibProxyMain.java:75)
    
  3. CGLIB 性能优于 JDK 代理。

    基于上述的代码,删除控制台打印命令,分别对 CGLIBJDK 两种代理方式执行 5 组,每组循环调用一千万次代理方法的任务。

    for (int i = 0; i < 5; i++) {
        long start = System.currentTimeMillis();
        for (int j = 0; j < 10000000; j++) {
            proxyInterface();
            proxyObject();
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start));
    }
    

    统计得到的耗时结果如下:

    # CGLIB 输出
    耗时:7409
    耗时:4137
    耗时:4211
    耗时:4146
    耗时:4018
    
    # JDK 输出
    耗时:10784
    耗时:9181
    耗时:9586
    耗时:9325
    耗时:9111