Spring aop 基于JDK动态代理和CGLIB代理的原理以及为什么JDK代理需要基于接口

本文是根据《深入分析Java Web技术内幕》一书第十三章探讨

Spring Aop是什么

简单来说就是面向切面编程。Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现。

JDK动态代理

JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。代理的目的是调用目标方法时可以转而执行InvocationHandler的invoke方法,实际上spring aop也是在这里做文章。这也是典型的代理模式
下面简单代码说明这个问题

  • 实现自己的InvocationHandler
/** * * @author yvan * */
public class AopProxy implements InvocationHandler {

    private Object realObject;


    public AopProxy(Object realObject) {
        super();
        this.realObject = realObject;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do something before execute invoke method...");
        Object invokeResult= method.invoke(realObject, args);
        System.out.println("do something after execute invoke method...");
        return invokeResult;
    }

}
  • 制定接口以及其实现类
/** * * @author yvan * */
public interface SubObject {
    public String execute(String... param);
}

/** * * @author yvan * */
public class RealObject implements SubObject {

    @Override
    public String execute(String... param) {
        for (int i = 0; i < param.length; i++) {
            System.out.println(param[i]);
        }
        return "execute method";
    }

}
  • 测试动态代理
/** * * @author yvan * */
public class AppMain {
    public static void main(String[] args) {
        SubObject realObject = new RealObject();
        AopProxy aopProxy = new AopProxy(realObject);
        // 通过jdk提供的proxy生成代理
        SubObject subObject = (SubObject) Proxy.newProxyInstance(aopProxy.getClass().getClassLoader(),
                realObject.getClass().getInterfaces(), aopProxy);
        System.out.println(subObject.getClass().getName());
        System.out.println(subObject instanceof Proxy);
        String result =  subObject.execute("参数一","参数二");
        System.out.println(result);
    }
}
  • 打印结果
com.sun.proxy.$Proxy0
true
do something before execute invoke method...
参数一
参数二
do something after execute invoke method...
execute method

着重说明一下:看到com.sun.proxy.$Proxy0是jdk动态生成的代理类,subObject instanceof Proxy打印为ture说明这个代理类继承了Proxy。
这里遇到一个疑问:为什么jdk动态代理必须基于接口
原因如下:
1、生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现
2、从代理模式的设计来说,充分利用了java的多态特性,也符合基于接口编码的规范
当然,jdk在生成代理的参数中也说明了,需要传入对应接口

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

CGLIB代理

CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理。

添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
    原文作者:AOP
    原文地址: https://blog.csdn.net/upxiaofeng/article/details/79035493
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞