春5.xのソース旅行四〇から九AOP通知メソッドの実行順序のお問い合わせ

どのようにAOPの通知方法の実行

全体を見てAOP、通知の基本的な方法の実行順序の内部構造:
ここに画像を挿入説明
我々が取るJDK動的プロキシは、例えば、CGLIBメソッドを呼び出すとき、それはなります、似ているJdkDynamicAopProxyのエージェントinvokeの実行:

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

バンチは、実際には、重要なので、いくつか、最初にすべてのすべての通知を取得List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);し、その後にパッケージ化ReflectiveMethodInvocation呼び出しproceed方法。私は、あなたが、より複雑な、実際には、コールスタックの順番を形成するために、私は背中を引き出すだろう研究を行くことができ、どのようにソートに特異的に、彼はすでに完成順序です費やす必要があり、あなたが見ることができるAOPの一般的なアプローチを置きます私たちは、実際には、これらの使用に最初のと何も具体的に見て、彼は第二の実施を指示し、その後、この順序で実行するために行くだろう。
ここに画像を挿入説明

実行サイクルのReflectiveMethodInvocationが進みます

メインは、再帰的なGET通知され、その後、実行しました。

@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的呼び出し

私は主に、しませんでしたmi.proceed()呼び出しを続け、つまり、ReflectiveMethodInvocation的proceed再帰呼び出しを行います。

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

AspectJAfterThrowingAdviceは、例外通知を呼び出します

実際には、パンキャッチ例外の外側の層は、その呼に引き続きmi.proceed();キャプチャすることができ、異常が実行する場合は、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;
		}
	}

invokeAdviceMethodのAbstractAspectJAdvice通知方法

実際には、これは限り通知方法が呼び出されるように、この内部でこれを呼び出すための最後の呼び出しになり、通知の一般的な方法です。
ここに画像を挿入説明

予告呼び出しAfterReturningAdviceInterceptorの成功復帰した後、

ただ、帰国プラスメソッドの後に内部を呼び出すことです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メソッド通知

これは、実行の実装後に、ですinvokeAdviceMethod

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

AspectJAroundAdviceは、周りのアドバイスを呼び出します

これは置くMethodInvocationにパッケージをProceedingJoinPointした後、呼び出された時にパラメータとして渡します。

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

まずパッケージ:
ここに画像を挿入説明
使用後は:
ここに画像を挿入説明
その後、おそらく機関は、ソースデータにそれを保護し、その後、呼び出すために、そこに複製されますproceed
ここに画像を挿入説明

MethodBeforeAdviceInterceptorのinvokeメソッド通知の前に

方法最初の通知メソッドを呼び出す前に、メソッドを呼び出します。

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

バックを実行する方法のエージェントに囲まれているため、基本的なプロセスは、なぜ正面に囲まれているので、ダウンして、事前に行われる処理囲む前に:
ここに画像を挿入説明
:例外が言っている場合
ここに画像を挿入説明
:全体の構造を見てはこれです
ここに画像を挿入説明HM6Ly9ibG9nLmNzZG4ubmV0L3dhbmd3ZWkxOTg3MTEwMw == 、size_16、color_FFFFFF、t_70)は
、通常、珍しいことではないこと、何の問題を制御することができます。
例外に表示されるのであればSystem.out.println("方法调用");このように直接実行System.out.println("logAfter");、実行は行かないlogReturningに直接catch情報がアップにもある場合は例外で、内部。

まあ、基本的なAOP通知は、ソート、再帰呼び出しに、実際には良い方法である後にコール分析は、以上です。実際には、のような他の機能があるDeclareParentstargetargsおよび他の注釈は、この基盤と、それだけで素晴らしい、難しい自分の研究すべきではありません。

さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。

公開された235元の記事 ウォン称賛74 ビュー30000 +

おすすめ

転載: blog.csdn.net/wangwei19871103/article/details/105230897