理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory

Spring AOP的底层是基于JDK和CGLIB代理技术来实现的,要理解Spring AOP,需要先对JDK和CGLIB有一定的认识和理解。

一. JDK动态代理

先看一段Demo示例,首先定义一个接口:

public interface DemoInterface {
    public void service();
}

该接口的实现:

public class DemoImpl implements DemoInterface {
    @Override
    public void service() {
        System.out.println("do service");
    }
}

定义一个InvocationHandler的实现类:

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

public class DemoInvocationHandler implements InvocationHandler {
    private Object obj;
    public DemoInvocationHandler(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Start.");
        Object result = method.invoke(obj, args);
        System.out.println("End.");
        return result;
    }
}

看看效果:

import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        DemoImpl demoImpl = new DemoImpl();

        DemoInterface demoInterface = (DemoInterface) Proxy.newProxyInstance(demoImpl.getClass()
                .getClassLoader(), demoImpl.getClass().getInterfaces(),
                new DemoInvocationHandler(demoImpl));
        demoInterface.service();
        System.out.println(demoInterface.getClass());
    }

}

控制台输出:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可见这个代理类已经按我们的设计工作了,最后一个输出是代理类的Class Name,可以看到是class com.sun.proxy. Proxy0 Proxy0。

接下来探秘一下这个动态代理是如何实现的,进入Proxy.newProxyInstance()函数看看源码,比较关键的是这句:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

这里生成了代理类的Class对象,跟进这个方法,会跟进到Proxy类里面的内部类ProxyClassFactory里面的apply方法中,关键片段是这里:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

先看这个ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags),源码:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可以看出来这实际在根据一些信息直接生成class的byte[]数组,就是前面所说的 com.sun.proxy.$Proxy0.class(有兴趣可以展开localProxyGenerator.generateClassFile()看看如何生成的class文件)。

ProxyClassFactory里面的apply方法中的另一个关键方法是defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);,看看源码:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

已经是一个native方法了,作用就是把class文件加载进来。
可以看出,com.sun.proxy.$Proxy0实际上是JDK根据既定规则直接生成class文件,然后像加载其他class文件一样加载进来,这就动态生成了一个类。

理解了代理类的动态生成,还有一个关键点是代理类如果跟InvocationHandler实现方法调用的拦截,回到Proxy.newProxyInstance()函数的最后一行:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可见InvocationHandler是作为构造函数的参数被传入的,可以理解,其实在生成com.sun.proxy. Proxy0com.sun.proxy. Proxy0定义了规则,使其接受InvocationHandler是作为构造函数的参数。

二. CGLIB动态代理

搞清楚JDK动态代理后,再看看CGLIB动态代理。从上面可以看出,JDK动态代理是需要一个接口和相应实现类的,如果没有接口,只有实现类,JDK动态代理就没法创建代理对象了,这个时候需要CGLIB动态代理。

先看一段Demo示例
被代理类:

public class DemoClass {
    public void service() {
        System.out.println("do service");
    }
}

InvocationHandler的实现类:

import java.lang.reflect.Method;

import net.sf.cglib.proxy.InvocationHandler;

public class DemoInvocationHandler implements InvocationHandler {
    private Object obj;
    public DemoInvocationHandler(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Start.");
        Object result = method.invoke(obj, args);
        System.out.println("End.");
        return result;
    }
}

跟jdk动态代理的InvocationHandler基本一样,不过要注意这里是net.sf.cglib.proxy.InvocationHandler接口。

最后看看Main类:

import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {
        DemoClass demoClass = new DemoClass();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DemoClass.class);
        enhancer.setCallback(new DemoInvocationHandler(demoClass));
        DemoClass proxy = (DemoClass) enhancer.create();
        proxy.service();
        System.out.println(proxy.getClass());
    }
}

输出结果如下:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可见代理已经正确工作了,并且生成了一个动态代理类:com.liuxiang.j2se.jdemo.proxy.cglib.demo.DemoClass

EnhancerByCGLIB 1b87eda0

CGLIB的原理和JDK动态代理的原理基本差不多(当然代码实现上差别很大),都是根据规则动态生成代理类class的byte[]数组,然后使用classLoader进行加载,有兴趣可以去看看源代码一探究竟。

三. ProxyFactory

Spring AOP在底层同时使用JDK,CGLIB动态代理技术,默认情况下,对实现了接口的类使用JDK代理,对没有实现接口的类使用CGLIB代理,实际也可以用参数进行控制。

另外,无论JDK动态代理,还是CGLIB动态代理,都需要实现一个InvocationHandler接口,显然这个接口更贴近代理机制本身,跟AOP机制那些概念相去甚远。

所以Spring实现了ProxyFactory,封装了底层的JDK,CGLIB代理技术(以及选择哪种代理技术),封装了AOP的通知Advice到InvocationHandler的转化。

看下Demo程序

一个接口:

public interface Pojo {
    public void foo();
}

接口的实现类SimplePojo:

public class SimplePojo implements Pojo {
    @Override
    public void foo() {
        System.out.println("SimplePojo.foo");
    }
}

一个相似的类SimplePojoNoInterface,但没有实现任何接口:

public class SimplePojoNoInterface {
    public void foo() {
        System.out.println("SimplePojoNoInterface.foo");
    }
}

新建一个BeforeAdvice:

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class DemoAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before advice");
    }
}

然后使用ProxyFactory分别为其生成代理:

import org.springframework.aop.framework.ProxyFactory;

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new DemoAdvice());
        Pojo pojo = (Pojo) factory.getProxy();

        ProxyFactory factory2 = new ProxyFactory(new SimplePojoNoInterface());
        factory2.addAdvice(new DemoAdvice());
        SimplePojoNoInterface simplePojoNoInterface = (SimplePojoNoInterface) factory2.getProxy();

        pojo.foo();
        System.out.println(pojo.getClass());

        simplePojoNoInterface.foo();
        System.out.println(simplePojoNoInterface.getClass());
    }
}

运行结果如下:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可见ProxyFactory为有接口的SimplePojo生成了JDK动态代理,为没有接口的SimplePojoNoInterface生成了CGLIB动态代理,并且都成功织入了DemoAdvice。

看看DefaultAopProxyFactory的createAopProxy方法:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可以看到这里就是选择使用JDK代理还是CGLIB代理。

JdkDynamicAopProxy(config);是对JDK动态代理的封装,在参数config中包含了advice信息,在JdkDynamicAopProxy里面会实现advice向InvocationHandler的转换,JdkDynamicAopProxy本身就是InvocationHandler的实现类,看看invoke方法的关键片段:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》
可以看出来这里其实是生成了一个方法调用链,来织入多个Advice。

再看看CglibAopProxy的实现:
《理解Spring AOP 原理(二)JDK,CGLIB动态代理以及ProxyFactory》

可见Enhancer本身支持设置多个callback,所以CGLIB的实现要相对简洁一点

    原文作者:AOP
    原文地址: https://blog.csdn.net/liuxiang87/article/details/53957037
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞