盘点AOP:AOP的拦截与方法调用

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 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 对象体系 :

System-MethodMatcher.png

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);

image.png

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 体系结构 :
Advisor-system.png

总结

到了这一篇 AOP 的主要逻辑就全部完成了 , 后续准备说说AOP 的性能分析以及补充知识点 , 等全部完成后 , 再对 AOP 逻辑进行一遍打磨

现阶段程度只是读懂了代码 , 只能看懂为什么这么用 . 等打磨的时候 ,期望能从中学到一些代码的设计精髓 , 以及写一套出来