首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> ???
文章合集 : ? juejin.cn/post/694164…
Github : ? github.com/black-ant
一 . 前言
之前说了 AOP初始化 和 AOP 代理类的创建 , 这一篇来看一下 AOP 对请求的拦截
AOP 拦截的起点是 DynamicAdvisedInterceptor , 该对象在 CglibAopProxy -> getProxy -> getCallbacks
二 . 拦截的发起
2.1 CglibAopProxy 的拦截开始
C- DynamicAdvisedInterceptor # intercept
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 仅保留核心方法 , 可以看到这里构建了 CglibMethodInvocation用于调用
Object retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
复制代码
2.2 Interceptor 执行 Proceed
上一节创建后 CglibMethodInvocation 后 , 会执行 proceed , 以此调用切面类 , 此处先以 Around 为例 , 后面再看一下其他的几种调用
Step 1 : Proceed 调用逻辑 (ReflectiveMethodInvocation)
主要是调用父类的逻辑 CglibMethodInvocation extends ReflectiveMethodInvocation
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 2.2.1 获取具体的 Advice , 此处通过自增完成拦截链的切换
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态方法匹配器-> Pro22101
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}else {
// 2.2.2 调用 Advice 的 invoke 方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
// Pro22101 : InterceptorAndDynamicMethodMatcher 的作用
class InterceptorAndDynamicMethodMatcher {
// 方法拦截器
final MethodInterceptor interceptor;
// 方法匹配器
final MethodMatcher methodMatcher;
}
复制代码
MethodMatcher 对象体系 :
Step 2 : ExposeInvocationInterceptor
这里是通过 ExposeInvocationInterceptor(CglibMethodInvocation) 调用 , 该拦截器的作用为 将当前MethodInvocation公开为本地线程对象的拦截器
private static final ThreadLocal<MethodInvocation> invocation =new NamedThreadLocal<>("Current AOP method invocation");
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
// 线程设置
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
复制代码
Step 3 : 调用不同的拦截链
从 2.2 步骤中 , 会通过自增的方式迭代拦截器 :
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
PS : 通常链式结构是递归执行的 , 通常最先执行的在列表最后
// 调用对应的 xxxAdviceInterceptor -> [Pro25001]
复制代码
[Pro25001] : Advice 拦截链的调用
// 此处会对不同的 Advice 进行处理 , 核心带入如下 :
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
从 interceptorsAndDynamicMethodMatchers 可以看到 , 如果存在 Advice 就会存在相关对象
复制代码
Step 4 : 反射到 Advice Method
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 调用实际业务方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
} catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
// 拦截适配器用于把通知转换为拦截器
// 主要的适配器 :
C- MethodBeforeAdviceAdapter
// 补充 invokeAdviceMethodWithGivenArgs 带参数访问
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
}
PS: 至此就完成了 Advice 方法的调用
复制代码
2.3 补充其他通知的调用方式
AspectJAfterAdvice 的调用
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// Step 1 : 链式调用走流程
return mi.proceed();
} finally {
// Step 2 : finally 完成最终调用
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
复制代码
AfterReturningAdviceInterceptor 的调用
public Object invoke(MethodInvocation mi) throws Throwable {
// Step 1 : 链式调用走流程
Object retVal = mi.proceed();
// Step 2 : 调用 afterReturning
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
复制代码
三 . 方法的调用
以 Around 为例 , 当执行了 ProceedingJoinPoint.proceed() 方法后 , 即开始了实际方法的调用
- Step 1 : 切面调用 pj.proceed()
- Step 2 : MethodInvocationProceedingJoinPoint 发起 proceed 操作
- Step 3 : 循环完成 , 发起方法调用
- Step 4 : 实际方法调用
3.1 MethodInvocationProceedingJoinPoint 发起 proceed 操作
PS : 此处还没有完成 , 这是构建了一个新的对象 , 从上一个链表图中可以看到 , 还要执行后续的 Before Advice
public Object proceed() throws Throwable {
return this.methodInvocation.invocableClone().proceed();
}
// PS : invocableClone 的作用
// 解答 : 此处创建了一个浅克隆 , 用于构建一个独立的拦截器 , 并且用于后续索引 , 但是其中的引用被保持
public MethodInvocation invocableClone() {
Object[] cloneArguments = this.arguments;
if (this.arguments.length > 0) {
// 虽然没有传入参数, 但是实际上构建函数中已经传入了
cloneArguments = this.arguments.clone();
}
return invocableClone(cloneArguments);
}
// C- MethodInvocationProceedingJoinPoint
public MethodInvocation invocableClone(Object... arguments) {
// 强制初始化用户属性Map,以便在克隆中有一个共享的Map引用
if (this.userAttributes == null) {
this.userAttributes = new HashMap<>();
}
// 创建MethodInvocation克隆对象
try {
ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
clone.arguments = arguments;
return clone;
} catch (CloneNotSupportedException ex) {
throw new IllegalStateException(...);
}
}
复制代码
3.2 Interceptor 循环完成 , 发起方法调用
补充 ReflectiveMethodInvocation 对象结构 >>
- ReflectiveMethodInvocation : 基于反射的方式,代理方法调用实现类。
I- ProxyMethodInvocation : 代理方法调用接口
M- #proceed() : 执行方法。基于递归的方式,调用每个拦截器链中的拦截器,最后调用真正的方法。
M- #invokeJoinpoint() : 执行真正的方法,即切点的方法。
M- CglibMethodInvocation : 基于CGLIB 的方式,进一步优化调用的实现类。
复制代码
当循环迭代完成后(currentInterceptorIndex匹配完成) :
public Object proceed() throws Throwable {
// 我们从一个索引-1开始,并提前递增 , 当全部递增完成后 , 意味着切面全部完成
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// ..........
}
复制代码
3.3 发起实际方法调用
// Step 3 : 实际方法调用 (2.1 中初始化了该属性)
private final MethodProxy methodProxy;
// 代理方法
protected Object invokeJoinpoint() throws Throwable {
if (this.methodProxy != null) {
return this.methodProxy.invoke(this.target, this.arguments);
} else {
return super.invokeJoinpoint();
}
}
复制代码
3.4 补充 : 带参数的请求
在 MethodInvocationProceedingJoinPoint 中 ,存在一个带参数的 proceed 方法 , 用于构建带参数的 clone 对象
// 除了无参的请求 , 实际上还有个带参的请求 , 他们的请求方式是不一样的
Object proceed(Object[] args)
public Object proceed(Object[] arguments) throws Throwable {
// 首先会校验参数是否存在和长度是否一致 , 这里省略
this.methodInvocation.setArguments(arguments);
return this.methodInvocation.invocableClone(arguments).proceed();
}
// 回顾clone 方法 , 有个变长参数
public MethodInvocation invocableClone(Object... arguments) {
//.............
}
// 这里和上面一样最终是 clone 了一个 ReflectiveMethodInvocation 出来 , 但是为其设置了独立的参数
复制代码
直到这里 , AOP 的方法调用就完全完成了 >>
四 . 补充 AOP 的拦截链构建
这里补充看一下 AOP 链的调用逻辑
C- AdvisorChainFactory : 通知链工厂
C- DefaultAdvisorChainFactory : 实现类
4.1 DynamicAdvisedInterceptor # intercept 发起拦截链构建
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//... 省略其他的逻辑
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
}
复制代码
4.2 从缓存中获取拦截器
这里会优先从缓存中获取 , 缓存没有会先创建 ,再放入缓存
// 缓存集合
private transient Map<MethodCacheKey, List<Object>> methodCache;
C- AdvisedSupport # getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
// 缓存没有则直接创建 , 并且放入缓存
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
复制代码
4.3 构建通知链
C- DefaultAdvisorChainFactory
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 注册Advisor适配器的接口 , 该接口是一个 SPI 接口
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 从 Advised 中获取通知者
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
// 如果为切点则执行
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校验是否匹配目标类
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
// 通过切点获取拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// IntroductionAdvisor 通过AOP通知实现额外的接口
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// org.springframework.aop.interceptor.ExposeInvocationInterceptor
return interceptorList;
}
复制代码
Advisor 体系结构 :
总结
到了这一篇 AOP 的主要逻辑就全部完成了 , 后续准备说说AOP 的性能分析以及补充知识点 , 等全部完成后 , 再对 AOP 逻辑进行一遍打磨
现阶段程度只是读懂了代码 , 只能看懂为什么这么用 . 等打磨的时候 ,期望能从中学到一些代码的设计精髓 , 以及写一套出来