• 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
  • 相关阅读:
    一个用java的get请求
    【总结】shell 脚本命令执行结果赋值给变量无效
    【算法】选择排序
    Cannot find module ‘core-js/modules/es6.regexp.constructor‘
    ProE 5.0免安装版软件安装教程
    关于docker无法正常下载镜像的问题
    Discourse 的关闭主题(Close Topic )和重新开放主题
    Pikachu漏洞练习平台之XXE(XML外部实体注入)
    Linux中vim编译器
    前端的(typeScript)interface详解(个人学习用)
  • 原文地址:https://blog.csdn.net/qq_43141726/article/details/127433162