【源码】Spring AOP 2 Advice
前言
aopalliance AOP联盟,一个定义了 AOP 规范接口的开源项目。本文从 Advice 接口出发,理解并深入其对 AOP Advice 的抽象。
Advice
public interface Advice {
}
Advice 是一个标记接口,位于最顶层
Interceptor
Interceptor ,也是个标记接口,我们上一文提到,通常在 AOP 规范下会将所有的通知维护成 Join point 上的 Interceptors Chain (拦截链)。
可以看到,有两个大的分支(MethodInterceptor 和 ConstructorInterceptor),即 AOP 支持方法级别和构造器级别的拦截。实际上,Spring AOP 并未(但完全可以)实现构造器级别的拦截,因为 Spring AOP 旨在让 AOP 的思想尽可能轻量、单纯地的与 Spring IOC 契合,而并非想要完完全全的实现一整套的 AOP。因此本文也只分析 MethodInterceptor
MethodInterceptor
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
- 函数式接口声明
MethodInterceptor
可以看作整个方法的调用链,因此invoke
是整个调用链的执行,这意味着其中那个包括源方法和Advice
的执行,下文结合具体实现类理解MethodInvocation
可理解为你要通知的对象。结合上一章节,不难理解其实它就是Join point
。以后会介绍到,很重要的一个分支。
BeforeAdvice
public interface BeforeAdvice extends Advice {
}
又一个标记接口,这个猜也能猜到,Before advice 的抽象
MethodBeforeAdvice
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
方法前置通知抽象,before 方法就是要执行的前置通知逻辑。上文说过,before 不能打断方法执行,除非抛出异常
AfterAdvice
public interface AfterAdvice extends Advice {
}
后置通知的抽象,标记接口
AfterReturningAdvice
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
After returning advice 的抽象,可以看到,他是允许对返回值进行操作的。
具体实现类
基本上,整个接口的抽象及关系,我们做了简单地梳理。然后结合具体的几个实现类再深入体会
AfterReturningAdviceInterceptor
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
- 它是一个
MethodInterceptor
又是一个AfterAdvice
,实际上是一个组合的关系 - 整个
Interceptor
调用时,在MethodInvocation#proceed
之后执行通知逻辑afterReturning
AfterReturning
通知支持对方法返回值进行干涉
MethodBeforeAdviceInterceptor
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
- 跟
AfterReturningAdviceInterceptor
类似,MethodInterceptor
和BeforeAdvice
Before
通知不能干涉返回值
ThrowsAdviceInterceptor
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
// 通知类
private final Object throwsAdvice;
/**
* K:异常类型
* V:处理该类型异常的方法
*/
private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<>();
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
Method[] methods = throwsAdvice.getClass().getMethods();
/**
* 对应的 Advice 提供的处理异常方法名必须为 afterThrowing,对应参数为 1 个或 4 个,q签名格式:
* void afterThrowing([Method, args, target], ThrowableSubclass)
*/
for (Method method : methods) {
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
// 去最后一个参数就是异常类型
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
if (Throwable.class.isAssignableFrom(throwableParam)) {
this.exceptionHandlerMap.put(throwableParam, method);
}
}
}
}
// ...
@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
/**
* 根据抛出的异常类型调用对应的 Advice 方法
*/
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
@Nullable
private Method getExceptionHandler(Throwable exception) {
Class<?> exceptionClass = exception.getClass();
// 找不到当前类型的处理器就依次找父类的,直到 Throwable
Method handler = this.exceptionHandlerMap.get(exceptionClass);
while (handler == null && exceptionClass != Throwable.class) {
exceptionClass = exceptionClass.getSuperclass();
handler = this.exceptionHandlerMap.get(exceptionClass);
}
return handler;
}
// ...
}
- 忍不住把所有代码贴了上来,
ThrowsAdviceInterceptor
的实现稍微复杂一点,它维护一个通知类Object throwsAdvice
和一个具体异常与通知方法对应关系的Map<Class<?>, Method> exceptionHandlerMap
,Object throwsAdvice
意味着可以是任何类 - 构造方法中基于所有
Object throwsAdvice
的签名符合void afterThrowing([Method, args, target], ThrowableSubclass)
的方法,构造exceptionHandlerMap
把异常和对应的通知方法关联起来 - 因此
invoke
的逻辑实现就是在目标方法抛出异常后找到对应的异常处理方法来处理,找不到的话会依次追溯它的父类 - 最后目标异常还是会抛出去
demo
public static class ThrowsAdviceSample {
public void afterThrowing(IndexOutOfBoundsException ex) {
System.out.println("catch IndexOutOfBoundsException");
}
public void afterThrowing(ExpressionException ex) {
System.out.println("catch ExpressionException");
}
}
@Test
public void test1() throws Throwable {
ThrowsAdviceInterceptor throwsAdviceInterceptor = new ThrowsAdviceInterceptor(new ThrowsAdviceSample());
throwsAdviceInterceptor.invoke(
new MethodInvocation() {
// ...
@Override
public Object proceed() throws Throwable {
throw new ArrayIndexOutOfBoundsException();
}
// ...
}
);
}
- 拿
ThrowsAdviceInterceptor
示例,异常通知可以定义任意类型,只要方法符合签名规则即可,比如示例中的ThrowsAdviceSample
- 方法执行抛出
ArrayIndexOutOfBoundsException
后会被其父类IndexOutOfBoundsException
的通知拦截,输出catch IndexOutOfBoundsException
类图
总结
忽略 AspectJ
下的实现,可以发现,这组接口的实现类多是 MethodInterceptor
和 Advice
的组合,前者负责整个调用链的执行,后者负责在恰当的时机执行通知
同时,MethodInterceptor
持有的 MethodInvocation
,就是下一章节要了解的 Joinpoint
上一篇:【源码】Spring AOP 1 基础概念
下一篇:【源码】Spring AOP 3 Joinpoint
参考
【小家Spring】Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor(引介增强)
【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、MethodInterceptor…