AOC概述
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
Advice通知
Advice定义在连接点做什么,为切面增强提供织入接口。它主要描述Spring AOP围绕方法调用而注入的切面行为。
增强(advice)主要包括如下五种类型
1. 前置增强(BeforeAdvice):在目标方法执行前实施增强 2. 后置增强(AfterReturningAdvice):在目标方法执行后实施增强 3. 环绕增强(MrthodInterceptor):在目标方法执行前后实施增强 4. 异常抛出增强(ThrowsAdvice):在目标方法抛出异常后实施增强 5. 引介增强(IntroductionIntercrptor):在目标类中添加一些新的方法和属性Pointcut切点
Pointcut(切点)决定Advice通知应该作用于哪个连接点。
Advisor通知器
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合在一块,完成这个作用的就是Advisor(通知器)。Advisor定义应该使用哪个通知并在哪个关注点使用它,将Advice注入程序中Pointcut位置。
AopProxy对象建立
通过配置和调用spring的ProxyFactoryBean来完成代理对象的生成,可以使用JDK的Proxy和CGLIB两种方式生成。
ProxyFactoryBean生成AopProxy代理对象
ProxyFactoryBean是一个FactoryBean, 用来配置目标对象和切面行为。在ProxyFactoryBean中, 通过interceptorNames属性来配置已经定义好的通知器Advisor, 还需要为target目标对象生成Proxy代理对象,从而为AOP横切面编制好准备工作。
在FactoryBean中获取对象, 是以getObject()方法作为入口完成的,也是通过该方法对target目标对象进行增强处理来为AOP功能的实现提供服务。getObject方法首先对通知链进行初始化,通知链封装了一系列拦截器,这些拦截器都在配置中读取。
Spring AOP拦截器调用实现
Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。
JDK的 Proxy来生成代理对象,需要通过Invocationhandler来设置拦截器回调;CGLIB生成代理对象,通过DynamicAdvisedInterceptor来完成回调。
JdkDynamicAopProxy的invoke拦截
invoke方法是JDK Proxy代理对象进行拦截回调的入口。invoke方法包含了一个完整的拦截链对目标对象的拦截过程,比如获得拦截器链并对拦截器链中的拦截器进行配送,逐个运行拦截器链中的拦截增强,直到最后对目标对象方法的运行等。
Cglib2AopProxy的intercept拦截
Cglib2AopProxy回调是在DynamicAdvisedInterceptor对象中实现,回调的实现在intercept方法中。实现类似上边的invoke方法。
AOP拦截器链的调用
AOP目标对象的增强封装在AOP拦截器链中,由一个个具体的拦截器来完成。两种代理对象对拦截器链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现。在proceed方法中,先进行判断,如果已经运行到拦截器链的末尾,就直接调用目标方法的实现方法;否则沿着拦截器链, 得到下一个拦截器,通过这个拦截器进行matches判断是否适用于横切增强的集合,如果是,从拦截器中得到通知器,并启动通知器的invoke方法进行切面增强,这个过程会迭代调用proceed方法。
配置通知器
advisor通知器的取得是委托给IOC容器完成的。ProxyFactoryBean通过回调容器的getBean去获取配置在Bean定义文件中的通知器。ProxyFactoryBean给出通知器的名字, 这些名字配置在interceptorNames的List中配置好。在IOC对FactoryBean进行依赖注入时,会直接注入到FactoryBean的interceptorNames的属性中。完成这个过程,ProxyFactoryBean就获得了配置的通知器,为未完成切面增强做好了准备。