Spring Aop 切面通知(Advice)的初始化和执行流程

文章目录

配置类

@Component
@Aspect
public class LogComponent {
    @Pointcut("execution(* com.test.UserService.*(..))")
    public void plc() {

    }
    @Before("plc()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("beforeLog:" + name);
    }
    @After("plc()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("afterLog:" + name);
    }
    @AfterReturning(value = "plc()", returning = "result")
    public void returning(JoinPoint jp, Object result) {
        String name = jp.getSignature().getName();
        System.out.println("returningLog:" + name);
        System.out.println("returningLog:" + result);
    }
    @AfterThrowing(value = "plc()", throwing = "e")
    public void throwing(JoinPoint jp, Exception e) {
        String name = jp.getSignature().getName();
        System.out.println("throwingLog:" + name);
        System.out.println("throwingLog:" + e.getMessage());
    }
    @Around("plc()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object proceed = pjp.proceed();
        String name = pjp.getSignature().getName();
        System.out.println("aroundLog:" + name);
        return proceed;
    }
}
@Component
@Aspect
public class TransactionComponent {
    @Pointcut("execution(* com.test.UserService.*(..))")
    public void plc() {

    }
    @Before("plc()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("beforeTransaction:" + name);
    }
    @After("plc()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("afterTransaction:" + name);
    }
    @AfterReturning(value = "plc()", returning = "result")
    public void returning(JoinPoint jp, Object result) {
        String name = jp.getSignature().getName();
        System.out.println("returningTransaction:" + name);
        System.out.println("returningTransaction:" + result);
    }
    @AfterThrowing(value = "plc()", throwing = "e")
    public void throwing(JoinPoint jp, Exception e) {
        String name = jp.getSignature().getName();
        System.out.println("throwingTransaction:" + name);
        System.out.println("throwingTransaction:" + e.getMessage());
    }
    @Around("plc()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object proceed = pjp.proceed();
        String name = pjp.getSignature().getName();
        System.out.println("aroundTransaction:" + name);
        return proceed;
    }
}

通知的初始化

Spring Aop 切面通知(Advice)的初始化和执行流程
对每个@Aspect切面类作处理

	public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = this.aspectBeanNames;
...
					for (String beanName : beanNames) {
					...
								MetadataAwareAspectInstanceFactory factory =
										new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
								List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
								if (this.beanFactory.isSingleton(beanName)) {
									this.advisorsCache.put(beanName, classAdvisors);
								}
								else {
									this.aspectFactoryCache.put(beanName, factory);
								}
								advisors.addAll(classAdvisors);
			...
	public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	...
		List<Advisor> advisors = new ArrayList<>();
		for (Method method : getAdvisorMethods(aspectClass)) {
			// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
			// to getAdvisor(...) to represent the "current position" in the declared methods list.
			// However, since Java 7 the "current position" is not valid since the JDK no longer
			// returns declared methods in the order in which they are declared in the source code.
			// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
			// discovered via reflection in order to support reliable advice ordering across JVM launches.
			// Specifically, a value of 0 aligns with the default value used in
			// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
			if (advisor != null) {
				advisors.add(advisor);
			}
		}

...
	}

根据@Pointcut注解确认方法适用范围并对切入点执行顺序排序

	private List<Method> getAdvisorMethods(Class<?> aspectClass) {
		final List<Method> methods = new ArrayList<>();
		ReflectionUtils.doWithMethods(aspectClass, method -> {
			// Exclude pointcuts
			if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
				methods.add(method);
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
		if (methods.size() > 1) {
			methods.sort(METHOD_COMPARATOR);
		}
		return methods;
	}

排序规则

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

	private static final Comparator<Method> METHOD_COMPARATOR;

	static {
		// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
		// an @After advice method will actually be invoked after @AfterReturning and
		// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
		// invokes proceed() in a `try` block and only invokes the @After advice method
		// in a corresponding `finally` block.
		Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
				new InstanceComparator<>(
						Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
				(Converter<Method, Annotation>) method -> {
					AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
					return (ann != null ? ann.getAnnotation() : null);
				});
		Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
		METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
	}

执行顺序

Spring Aop 切面通知(Advice)的初始化和执行流程

涉及类和顺序

频繁调用方法

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

	public Object proceed() throws Throwable {
		//获取下一个拦截器
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		//调用拦截器
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}

一个切面各个切点执行顺序

org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
...
				//根据调用方法和调用方法所在类,找出匹配的
				//Interception和Advice
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice, but just reflective invocation of the target.
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					// We can skip creating a MethodInvocation: just invoke the target directly.
					// Note that the final invoker must be an InvokerInterceptor, so we know
					// it does nothing but a reflective operation on the target, and no hot
					// swapping or fancy proxying.
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {
					// We need to create a method invocation...
					//根据拦截器chain处理调用目标方法
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		//当最后一个interceptor执行完后,调用目标方法
		//并退出
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//挨个执行拦截器链中的拦截器,从0开始
		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);
		}
	}

一定位于拦截器链执行的第一个,将当前调用上下文保存到线程本地,
供某些需要的切点获取这些信息
org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke


//Interceptor that exposes the current MethodInvocation as a thread-local object.
//We occasionally need to do this; for example, when a pointcut (e.g. an AspectJ expression pointcut) needs to know the full invocation context

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
			//执行下一个拦截器
			return mi.proceed();
		}
		finally {
			invocation.set(oldInvocation);
		}
	}

process()

org.springframework.aop.aspectj.AspectJAroundAdvice#invoke

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		//包装当前调用mi(CglibAopProxy$CglibMethodInvocation)
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		//调用环绕通知方法
		return invokeAdviceMethod(pjp, jpm, null, null);
	}
    @Around("plc()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    	//pjp.proceed();
    	//调用CglibAopProxy$CglibMethodInvocation.proceed()
        Object proceed = pjp.proceed();
        String name = pjp.getSignature().getName();
        System.out.println("aroundLog:" + name);
        return proceed;
    }

process()

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

	public Object invoke(MethodInvocation mi) throws Throwable {
		//调用before切入点的方法
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		//CglibAopProxy$CglibMethodInvocation.proceed()
		//调用下一个拦截器
		return mi.proceed();
	}

process()

org.springframework.aop.aspectj.AspectJAfterAdvice#invoke

	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			//继续调用下一个拦截器
			return mi.proceed();
		}
		finally {
			//调用链结束后,调用after切入点的方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

process()

org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor#invoke

	public Object invoke(MethodInvocation mi) throws Throwable {
		//继续调用下一个拦截器
		Object retVal = mi.proceed();
		//根据返回值调用afterReturn切入点方法
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

process()
org.springframework.aop.aspectj.AspectJAfterThrowingAdvice#invoke

	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
		//继续调用下一个
			return mi.proceed();
		}
		catch (Throwable ex) {
			//只有当抛出异常是切点方法参数的的子类型时才执行
			if (shouldInvokeOnThrowing(ex)) {
			//调用afterThrow切点方法
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

第二个切面也是这个执行顺序一个切面各个切点执行顺序

最后执行目标方法,开始退出
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

	public Object proceed() throws Throwable {
		//这时最后一个拦截器也执行过了
		//整个个拦截器链已经铺开
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		//执行被切面的方法,开始依次退出各个拦截器方法
			return invokeJoinpoint();
		}

Spring Aop 切面通知(Advice)的初始化和执行流程

前置通知例外,因为在拦截器链执行前,就已经调用过了
Spring Aop 切面通知(Advice)的初始化和执行流程
afterThrow只有在出现异常时才会执行
Spring Aop 切面通知(Advice)的初始化和执行流程

结果

beforeLog:getUserById
beforeTransaction:getUserById
getUserById
returningTransaction:getUserById
returningTransaction:user:1
afterTransaction:getUserById
aroundTransaction:getUserById
returningLog:getUserById
returningLog:user:1
afterLog:getUserById
aroundLog:getUserById
上一篇:c_lc_扑克牌顺子(模拟 / 思维)


下一篇:本地连接HDFS报地址解析异常 UnresolvedAddressException