AOP概念回顾
AOP是Aspect-Oriented Programming(面向方面编程或面向切面)的简称。
面向切面编程为我们提供了有别于面向对象的角度,来思考程序结构,通过这种方式来弥补面向对象的不足。
面向对象强调的是一切皆对象。同样我们也可以说面向接口,一切皆接口。面向服务一切皆服务。同理面向切面。
我们拿面向接口举例,强调的就是我们在开发中操纵的都是一些接口,而不去关心其具体实现。其实同理我们同理可以得到,面向切面即我们操纵的一切都是切面,不依赖流程。正是因为AOP这种特性我们可以优雅的解决一些在开发中遇到的问题。
在Spring中的AOP有如下几个核心接口
- Advice接口:Spring采用AOP联盟所定义的Advice作为一个父接口,扩展除了很多的子接口,BeforeAdvice,AfterAdvice等等,这些接口构成了Spring AOP的通知体系
- Pointcut接口:spring采用pointcut作为切点的抽象,切点决定的就是要切入哪些方法
- Advisor:通知器或者说通知者,按照正常逻辑,通知者必须知道它要通知什么,所以Adivsor依赖于Advice,Advisor的一个子接口PointAdvisor还依赖pointcut,也就是说这个接口确切的定义是包含了通知谁和通知什么,也就是说可以获得pointcut和advice。
Advice通知
在Spring中,使用了AOP联盟规定的Advice接口,Spring通过这个接口,还定义了更多的细化和扩展。比如BeforeAdvice,AfterAdvice,ThrowsAdvice。
BeforeAdvice
在BeforeAdvice体系中定义了一些接口和实现类,今天我们主要看一下MethodBeforeAdvice,前置增强接口,使用这个接口需要实现他的一个回调函数
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
这个方法的实现回下,Advice被配置到目标方法后,会在调用目标方法时被回调。具体参数:
- Method对象,目标方法的反射对象
- Object[]对象那个数组,这个数组中包含目标方法的输入参数
- target对象,方法的调用目标,可能为null
AfterAdvice
在AfterAdvice体系中同样也定义了一下接口和实现类,主要看一下AfterReturningAdvice,在这个接口中同样定义了一个回调方法
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
Spring会在这个接口实现中提供切面增强的具体设计,在这个Advice通知被正确配置以后,在目标方法嗲用结束并且成功返回的时候,接口就会被Spring AOP回调。
具体参数:
- returnValue:目标方法的返回结果
- method:目标方法的反射对象
- args:目标方法的参数。
在这个回调方法中,可以定义和before方法中同样的逻辑。虽然这两个方法中定义的逻辑是相同的,但是一个发生在方法调用之前,一个放发生在方法城东调用返回结果后。由此可见AOP为我们的应用带来的灵活性,使得相同的代码可以根据应用需要灵活的出现在不同场合。
ThrowAdvice
在ThrosAdvice中没有指定需要实现的方法,它在抛出异常的时候被回调,这个回调是AOP通过反射来完成的。
在ThrowsAdvice中可以定义一下几种接口
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
为什么不向我们before,afterReturning一样实现抽象接口呢,主要还是怕代码容易,因为一般我们实现接口的过程中用到的方法只有一个,如果都声明成为了抽象方法的,那么在实现接口的过程中也要实现这四个方法,显得冗余了。
Pointcut 切点
在介绍pointcut之前,我们还需要了解一个概念Join point(连接点),指的是程序运行中的某个阶段,如某个方法的调用、异常抛出等。
而我们现在所说的pointcut就是join point的一个集合,它是程序中需要注入Advice的集合,并且指明了advice要在什么样的条件下才能被触发。
我们来看看Pointcut这个接口是如何定义的
public interface Pointcut {
/**
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
从上面的代码块中我们可以看到,pointcut为我们提供了两个接口
- getClassFilter():用于将切入点限制在给定的目标类中。
- getMethodMatcher():用于判断切入点是否匹配目标类给定的方法。
首先我们看一下getMethodMatcher()返回的MethodMatcher是如何定义的
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method method, Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
在这个接口中定义了三个方法
- matches(Method method, Class<?> targetClass):对方法名进行匹配
- isRuntime():判断当前方法是否在运行时
- boolean matches(Method method, Class<?> targetClass, Object… args):对matches重写,增加了目标方法参数。
Advisor通知器
通常我们在完成目标方法的增强设计和关注点的设计以后,需要一个对象把它们结合起来,Adivsor就是做这个功能的。通过Advisor可以定义应该使用哪个通知并在哪个关注点使用它,也就是说我们可以通过Advisor,把Advice和pointcut结合起来,这个结合为使用IoC容器配置AOP应用,或者说即开即用地使用AOP基础设置,提供了遍历。
在Advisor接口中依赖了Advice,在Advisor的子接口pointAdvisor依赖了pointcut,也就是说这个接口更加确定的定位应该是包含了要通知谁和要通知什么。