• Spring Aop 源码 (三) (执行过程)


    1.执行入口

    在这里插入图片描述

    在这里插入图片描述

    调用了CglibAopProxy.DynamicAdvisedInterceptor.intercept() 方法

    在这里插入图片描述

    在这里插入图片描述

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
    • 1

    这个方法得到一个拦截器链, 是5个增强器封装成MethodInterceptor

    在这里插入图片描述

    然后 mi.proceed() 方法触发拦截器链的方法。

    在这里插入图片描述

    	@Override
    	@Nullable
    	public Object proceed() throws Throwable {
    		// We start with an index of -1 and increment early.
    		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    			return invokeJoinpoint();
    		}
    
    		Object interceptorOrInterceptionAdvice =
    				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    			// Evaluate dynamic method matcher here: static part will already have
    			// been evaluated and found to match.
    			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 {
    			// It's an interceptor, so we just invoke it: The pointcut will have
    			// been evaluated statically before this object was constructed.
    			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    最后的一个方法进入了 invoke(this), 进入了拦截器的责任链

    2.进入拦截器责任链

    1. ReflectiveMethodInvocation.proceed() ->
    2. ExposeInvocationInterceptor.invoke(mi) -> currentInterceptorIndex = 1
    3. MethodBeforeAdviceInterceptor.invoke(this) -> advice.before -> mi.proceed -> currentInterceptorIndex = 2
    4. AspectJAfterAdvice.invoke(this) -> return mi.proceed() -> finally invokeAdviceMethod -> currentInterceptorIndex = 3
    5. AfterReturningAdviceInterceptor.invoke(this) -> Object retVal = mi.proceed() -> this.advice.afterReturning(retVal) -> return retVal -> currentInterceptorIndex =4
    6. AspectJAfterThrowingAdvice.invoke(this) -> return mi.proceed() -> catch invokeAdviceMethod
    7. invokeJoinPoint() 执行连接点, 执行目标方法

    在这里插入图片描述

    ExposeInvocationInterceptor, MethodBeforeAdviceInterceptor, AspectJAfterAdvice, AfterReturningAdviceInterceptor, AspectJAfterThrowingAdvice为Filter类

    CglibMethodInvocation 为 FilterChain

    在这里插入图片描述

    2.1 ExposeInvocationInterceptor

    这个拦截器为暴露共享数据

    在这里插入图片描述

    ExposeInvocationInterceptor.invoke()

    先是 invocation.set(mi); 这里的invocation是一个threadLocal, 可以保存共享数据

    在这里插入图片描述

    又进入了ReflectiveMethodInvocation.proceed()

    2.2 MethodBeforeAdviceInterceptor

    前置通知拦截器

    MethodBeforeAdviceInterceptor.invoke()

    在这里插入图片描述

    先是执行了前置通知, 然后返回mi.procced()

    2.3 AspectJAfterAdvice

    后置通知拦截器

    AspectJAfterAdvice.invoke()

    在这里插入图片描述
    返回的是 mi.proceed(), 并进行 invokeAdviceMethod()

    2.4 AfterReturningAdviceInterceptor

    返回通知拦截器

    AfterReturningAdviceInterceptor.invoke()

    在这里插入图片描述

    2.5 AspectJAfterThrowingAdvice

    异常通知

    AspectJAfterThrowingAdvice.invoke()

    在这里插入图片描述

    2.6 invokeJoinPoint()

    执行连接点, 用于执行方法

    在这里插入图片描述

    3.执行顺序

    前置通知 => 目标方法 => 返回通知 => 后置通知

    前置通知 => 目标方法 => 异常通知 => 后置通知

    try{
    	前置通知
    	目标方法
    	返回通知
    }catch(){
    	异常通知
    }finally{
    	后置通知
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Linux:Termius连接本地虚拟机与虚拟机快照
    Clickhouse数据库应用
    Ubuntu 20.04 上 OpenStack 学习之 OVN : L2网络 ( Logical switches 逻辑交换机)
    LLM 为什么需要 tokenizer?
    12个微服务架构模式最佳实践
    数据化管理洞悉零售及电子商务——零售策略中的数据化管理
    Web前端和Java选哪个?哪个就业形势更好?
    昨天访问量破记录
    2022年9月2日:面向初学者的 web 开发--使用 JavaScript 制定决策
    Shell基本语法--流程控制
  • 原文地址:https://blog.csdn.net/qq_43141726/article/details/127433162