Spring ソースコード解析 (8) aop

私の他の Spring ソースコード分析: https://blog.csdn.net/caicongyang/category_2139981.html

核となるアイデア:

アドバイザー 
      ポイントカット
          クラスフィルター
          メソッドマッチャー
    アドバイス --> メソッドインターセプター

全体的なプロセス:


作成中の Bean --> インスタンス化後、メソッドは一致するアドバイザをすべて検索します --> メソッドがプロキシ ペアで実行されるときに、ProxyFactory を使用してプロキシ オブジェクトを生成します
--> 現在呼び出されているメソッドに基づいて、一致するアドバイザをすべて検索します --> > 対応するアドバイス ロジックを実行します。

1. cglib ダイナミック プロキシと jdk ダイナミック プロキシ

要点: インターフェイスには jdk を使用し、他のインターフェイスには cglib を使用します

2.@EnableAspectJAutoProxy

AnnotationAwareAspectJAutoProxyCreator を Bean ファクトリに追加します。

AnnotationAwareAspectJAutoProxyCreator は、AbstractAutoProxyCreator を継承し、BeanPostProcess です。初期化後のメソッド postProcessAfterInitialization で、初期 Bean に一致するアドバイスがあるかどうかが判断されます。存在する場合は、ProxyFactory プロキシ オブジェクトが生成されます。

その中で、AnnotationAwareAspectJAutoProxyCreator は findCandidateAdvisors() を書き換えて、すべての Advisor タイプを検索し、@Before およびその他のアノテーションをあらゆる側面から解析して Advisor オブジェクトを取得します。

3.プロキシファクトリー

ProxyFactory は Spring の動的プロキシのカプセル化です。JdkDynamicAopProxy
クラスの invoke メソッドは、一致する Advisor をフィルタリングして除外し、それを Interceptor に適応させ、それを責任のチェーンにカプセル化し、MethodInvocation の continue() メソッドで再帰呼び出しを行います。クラス;

CglibAopProxy にも同様のロジックがあります。

JdkDynamicAopProxyの呼び出しメソッドは以下のとおりです。

	@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 {
			// 如果接口中没有定义equals()方法,那么则直接调用,不走代理
			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...
				// 也是直接调用Advised接口中的方法,不走代理逻辑
				// 其实就是利用代理对象获取ProxyFactory中的信息
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
			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.
			// 代理对象在执行某个方法时,根据方法筛选出匹配的Advisor,并适配成Interceptor
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a 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.
				// 如果没有Advice,则直接调用对应方法
				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);
			}
		}
	}

おすすめ

転載: blog.csdn.net/caicongyang/article/details/122994273