前言:
首先,要了解 Spring 的 AOP 就必须先了解的动态代理的原理,因为 AOP 主要就是基于动态代理实现的。对动态代理有不明白的同学,可以看我的上一篇博客:代理设计模式(JDK和CGLIB)
AOP的概念:
AOP(Aspect Oriented Programming)是“面向切面编程”的简称,而面向切面编程其实就是一种关注点分离的技术。
关注点分离是什么意思呢?比如,我们在软件开发中,主要的注意点一般是在业务逻辑上,因为我们的代码就是实现某种特定的业务逻辑。但是我们往往不能只专注于我们想要实现的业务逻辑,比如我们写业务逻辑代码的同时,还要写诸如事务管理、安全管理、日志管理和调试管理等等等等通用化的功能,并且,每个我们本来要写的业务功能都要和这些通用的业务功能混在一起,是不是很崩溃?
这时,程序员的春天(Spring)来的,它所支持的AOP技术,将业务功能的关注点和通用化功能的关注点分离开来。这些通用化功能的代码实现,对应的就是我们说的切面(Aspect)。
AOP是如何实现的?
实现AOP的技术,主要分为两大类:
- 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
- 采用静态织入方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码
一般来说,Spring都是通过动态代理来实现代理类的。对动态代理有了解或者读过我上一篇博客的小伙伴们都知道,Java实现动态代理有两种方式:
- 基于JDK的动态代理
- 基于Cglib的动态代理
那么,Spring是用哪种方式来实现的呢?
- 当目标类是接口,则默认使用JDK动态代理技术。
- 否则则默认使用Cglib来生成代理。
- 当目标类是接口,也可以通过配置,强行使用Cglib来生成代理。不过一般没必要这样做。
实际项目开发中,一般讲究面向接口编程,这样的好处是很多的,因为不是这篇文章的重点,所以我不展开叙述。但是正是因为这样的编程风格,使得Spring的AOP一般都使用JDK实现动态代理。
Spring如何实现JDK动态代理
从上篇文章所讲述的JDK动态代理的原理可以知道,代理的目的是调用目标方法时我们可以转而执行 InvocationHandler 类的 invoke 方法,所以如何在 InvocationHandler 上做文章就是 Spring 实现 Aop 的关键所在。
Spring Aop 也是实现其自身的扩展点来完成这个特性的,代理类正是继承了 FactoryBean 的 ProxyFactoryBean,之前一篇Spring和他的IOC中讲过,FactoryBean 是特殊的Bean,而FactoryBean 之所以特别就在它可以让你自定义对象的创建方法。当然代理对象要通过 Proxy 类来动态生成。
下面是 Spring 创建的代理对象的时序图:
Spring 创建了代理对象后,当你调用目标对象上的方法时,将都会被代理到 InvocationHandler 类的 invoke 方法中执行,这在动态代理那一篇博客已经解释。在这里 JdkDynamicAopProxy 类实现了 InvocationHandler 接口。
目前我还没有对Spring如何实现使用CGLIB动态代理进行过研究,而且使用CGLIB有些不好的地方,比如使用的时候需要引入ASM开源包,而且无法对final修饰的类或者方法实现代理。感兴趣的朋友可以研究一下。