在说这节的重点前,我们回顾一下几个重要概念:
- 切面:封装了横切关注点的模块,包含通知和切点
- 通知:定义增强逻辑的代码,前置、后置、环绕等
- 切点:定义哪些方法需要被增强的匹配规则
那自然引出我们这节的重点,通知链
,通知链指的是当一个方法匹配多个通知的情况下,AOP将这些串成一个链来依次执行。那我们上文说的代理对象就是拦截目标方法然后来执行通知链。
Spring AOP的通知链执行逻辑高度依赖责任链模式
,通过链式调用协调多个通知的执行顺序,确保灵活性和扩展性,那下面我们具体来看下是如何实现的。另外,责任链模式是一种设计模式,而通知链是具体的应用,大家别搞混了。
1. 责任链模式特点
责任链模式是一种设计模式,也就是允许多个处理者依次处理请求,处理者决定是否处理还是给下一位,这个名字就很贴切,很符合链条式,比较核心的优点是:
- 能够解耦请求与处理:请求发送者无需知道处理者
- 动态组合:链上的处理者可以动态修改
- 顺序执行
那在AOP的通知链就完美契合责任链模式,每个通知 就是一个处理者 ,目标方法的调用 是请求,Spring通过代理对象将方法调用分发到通知链,通知按顺序执行。
2. Spring AOP通知链的执行流程
整个流程的调用链如下:
客户端调用->代理对象->通知链(Advice1->Advice2->Advice3......->目标方法)->返回结果
3. 通知链的构建与执行
SpringAOP的通知链实现在下面几个核心源码类里:
ReflectiveMethodInvocation
:管理通知链的执行,维护通知列表和调用状态CglibAopProxy和JdkDynamicAopProxy
:实现代理逻辑,触发通知链DefaultAdvisorChainFactory
:构建通知链
下面我们从这三个类入手来看一下这一块的内容:
3.1 通知链的构建
该DefaultAdvisorChainFactory 的核心方法是getInterceptorsAndDynamicInterceptors
scss
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
@Override
public List<Object> getInterceptorsAndDynamicInterceptors(
AdvisedSupport config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Advisor[] advisors = config.getAdvisors();
// 遍历所有 Advisor
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 检查切点是否匹配
if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) &&
pointcutAdvisor.getPointcut().getMethodMatcher().matches(method, actualClass)) {
// 获取通知并转换为拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
return interceptorList;
}
}
这里的关键是:首先通过AdvisedSupport 对Advisor 遍历,然后通过PointcutAdvisor的ClassFilter 和MethodMatcher判断方法是否需要增强,然后就是拦截器转换最后就是按优先级排序。
3.2 通知链的执行
该ReflectiveMethodInvocation 的核心方法为proceed
kotlin
public class ReflectiveMethodInvocation implements MethodInvocation {
protected final Object proxy;
protected final Object target;
protected final Method method;
protected Object[] arguments;
private final List<?> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;
public ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.method = method;
this.arguments = arguments;
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
@Override
public Object proceed() throws Throwable {
// 如果所有拦截器执行完毕,调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.target.getClass(), this.arguments)) {
return dm.interceptor.invoke(this);
} else {
return proceed(); // 跳过不匹配的拦截器
}
} else {
// 执行拦截器逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
}
关键点是:
链式调用
:proceed方法通过currentInterceptorIndex维护当前执行的拦截器的位置,递归调用形成链式执行拦截器执行
:每个拦截器(MethodInterceptor)通过invoke方法执行逻辑,并决定是否调用proceed继续链的执行目标方法调用
:当所有拦截器执行完毕,invokeJoinpoint通过反射调用目标方法动态匹配
:支持动态切点匹配,在运行时检查方法是否匹配
3.3 代理对象的拦截逻辑
这个我们在上篇文章说过,核心方法就是intercept:
typescript
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private final AdvisedSupport advised;
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 获取通知链
List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty()) {
// 无通知,直接调用目标方法
retVal = methodProxy.invoke(target, args);
} else {
// 创建 MethodInvocation,触发通知链
MethodInvocation invocation = new ReflectiveMethodInvocation(
proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
return retVal;
}
}
关键点是:
- 通知链获取:通过
AdvisedSupport
获取适用于当前方法的通知链 - MethodInvocation创建:封装代理对象、目标对象、方法、参数和通知链
- 链式调用:调用
ReflectiveMethodInvocation.proceed
触发通知链的执行
另外,Spring AOP默认按以下顺序来执行通知的:
@Around(前置)→ @Before → 目标方法 → @After → @Around(后置)
4. 总结
在整个源码中,有一些关键的优化,例如使用缓存、反射、拦截器统一拦截。那这篇文章主要有两个关键点,一个是通知链的构建
还有一个链式执行
。