春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
通知は、ソート、再帰呼び出しに、実際には良い方法である後にコール分析は、以上です。実際には、のような他の機能があるDeclareParents
、target
、args
および他の注釈は、この基盤と、それだけで素晴らしい、難しい自分の研究すべきではありません。
さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。