Spring 5.x Source trip forty-nine AOP notification method execution order inquiry

How AOP notification method execution

Look at the whole AOPinternal structure of the execution order of the basic methods of notification:
Here Insert Picture Description
We take a JDKdynamic proxy, for example, CGLIBis similar, when calling a method, it will be JdkDynamicAopProxythe agent of invokeexecution:

@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			
			MethodInvocation.
			if (chain.isEmpty()) {
				// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

Bunch, in fact, so few important, first of all get all notifications List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);and then packaged into a ReflectiveMethodInvocationcall proceedmethod. I put the general approach of AOP have to spend, you can see where he is already finished ordering, specifically how to sort, you can go study, the more complicated, in fact, in order to form a call stack order, I will draw out the back, we look at the use of these, in fact, nothing specific with first, he will direct the implementation of the second, and then go on to perform in this order:
Here Insert Picture Description

ReflectiveMethodInvocation of execution cycles proceed

The main is a recursive get notifications, and then executed.

@Override
	@Nullable
	public Object proceed() throws Throwable {
		// 循环执行,直到执行完
		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);
		}
	}

ExposeInvocationInterceptor的invoke

I did not do, primarily mi.proceed(), that is, continue to call ReflectiveMethodInvocation的proceedto make recursive calls.

@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
			return mi.proceed();
		}
		finally {
			invocation.set(oldInvocation);
		}
	}

AspectJAfterThrowingAdvice invoke the exception notification

In fact, the outer layer of bread catch the exception, then continue to call mi.proceed();, if an abnormality that can be captured to perform invokeAdviceMethod.

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

AbstractAspectJAdvice notification method of invokeAdviceMethod

In fact, this is a common method of notification, as long as the notification method to be called, will be the final call to call this inside this:
Here Insert Picture Description

After the successful return of AfterReturningAdviceInterceptor invoke notice

Just after returning plus method is to call the interior invokeAdviceMethod.

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

AspectJAfterAdvice invoke method notice

That is, after the implementation of execution invokeAdviceMethod.

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

AspectJAroundAdvice invoke the around advice

This will put MethodInvocationthe package into ProceedingJoinPoint, and then pass in as parameters when invoked.

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		return invokeAdviceMethod(pjp, jpm, null, null);
	}

First package:
Here Insert Picture Description
After use:
Here Insert Picture Description
Then there will be cloned, perhaps the agency to protect the source data it, and then call proceed:
Here Insert Picture Description

MethodBeforeAdviceInterceptor invoke method before notification

Before calling the method first notification method, calling the method.

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

The basic process is so down, so why is surrounded in the front, because the back surrounded by agents of the method to be performed, prior to surround processing carried out in advance:
Here Insert Picture Description
If an exception is to say:
Here Insert Picture Description
look at the whole structure is this:
Here Insert Picture DescriptionHM6Ly9ibG9nLmNzZG4ubmV0L3dhbmd3ZWkxOTg3MTEwMw == , size_16, color_FFFFFF, t_70)
normally can control, that is not unusual, nothing issue.
If an exception is to appear in System.out.println("方法调用");thus directly executed System.out.println("logAfter");, execution will not go logReturningdirectly into the catchinside, with an exception when information is also on the up.

Well, the basic AOPcall analysis is over, after the notice is actually a good method to sort, recursive calls. In fact, there are other features, such as DeclareParents, target, argsand other annotations, with this foundation, it should not be difficult, their own research just great.

Well, here today, we hope to help study and understand, do not spray the Great God see, understand only their own learning, limited capacity, please excuse.

Published 235 original articles · won praise 74 · views 30000 +

Guess you like

Origin blog.csdn.net/wangwei19871103/article/details/105230897