AOP詳解之三-建立AOP代理後記,建立AOP代理

程式設計師田同學發表於2022-03-24

AOP詳解之三-建立AOP代理後記,建立AOP代理。

上篇文章已經獲取到了AOP的資訊,接下來就是拿著這些AOP的資訊去建立代理了。

首先我們看下建立AOP代理的入口處。

//這個方法將返回代理類
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 1.判斷當前bean是否在targetSourcedBeans快取中存在(已經處理過),如果存在,則直接返回當前bean
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 2.在advisedBeans快取中存在,並且value為false,則代表無需處理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 3.bean的類是aop基礎設施類 || bean應該跳過,則標記為無需處理,並返回
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 4.獲取當前bean的Advices和Advisors
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 5.如果存在增強器則建立代理
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 建立代理...建立代理...建立代理...
			// 5.1 建立代理物件:這邊SingletonTargetSource的target屬性存放的就是我們原來的bean例項(也就是被代理物件),
			// 用於最後增加邏輯執行完畢後,通過反射執行我們真正的方法時使用(method.invoke(bean, args))
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 5.2 建立完代理後,將cacheKey -> 代理類的class放到快取
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		// 6.標記為無需處理
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

在5.1的位置開始建立代理物件,我們從此開始深入建立AOP代理的原始碼。

// 注意看這個方法的幾個引數,
	//   第三個引數攜帶了所有的 advisors
	//   第四個引數 targetSource 攜帶了真實實現的資訊
	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		// 建立 ProxyFactory 例項
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		// 檢查proxyTargetClass屬性,判斷對於給定的bean使用類代理還是介面代理,
		// proxyTargetClass值預設為false,可以通過proxy-target-class屬性設定為true
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		// 獲取Advisor顧問物件
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// 2.使用proxyFactory獲取代理
		return proxyFactory.getProxy(getProxyClassLoader());
	}

在2位置拿著我們new的代理工廠獲取我們的代理物件。

	public Object getProxy(@Nullable ClassLoader classLoader) {
		// 1.createAopProxy:建立AopProxy
		// 2.getProxy(classLoader):獲取代理物件例項
		return createAopProxy().getProxy(classLoader);
	}

第一步是獲取AOP的代理物件

/**
	 * 建立AOP物件的真正例項
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return
	 * @throws AopConfigException
	 */
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		// 1.判斷使用JDK動態代理還是Cglib代理
		// optimize:用於控制通過cglib建立的代理是否使用激進的優化策略。除非完全瞭解AOP如何處理代理優化,
		// 否則不推薦使用這個配置,目前這個屬性僅用於cglib代理,對jdk動態代理無效
		// proxyTargetClass:預設為false,設定為true時,強制使用cglib代理,設定方式:<aop:aspectj-autoproxy proxy-target-class="true" />
		// hasNoUserSuppliedProxyInterfaces:config是否存在代理介面或者只有SpringProxy一個介面
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			// 拿到要被代理的物件的型別
			Class<?> targetClass = config.getTargetClass();

			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			// 要被代理的物件是介面 || targetClass是Proxy class
			// 當且僅當使用getProxyClass方法或newProxyInstance方法動態生成指定的類作為代理類時,才返回true。
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				// JDK動態代理,這邊的入參config(AdvisedSupport)實際上是ProxyFactory物件
				// 具體為:AbstractAutoProxyCreator中的proxyFactory.getProxy發起的呼叫,在ProxyCreatorSupport使用了this作為引數,
				// 呼叫了的本方法,這邊的this就是發起呼叫的proxyFactory物件,而proxyFactory物件中包含了要執行的的攔截器

				return new JdkDynamicAopProxy(config);
			}
			// Cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			// JDK動態代理
			return new JdkDynamicAopProxy(config);
		}
	}

第二步是獲取真實的物件

我們接著看getProxy這個方法,該方法有兩個實現類。

image-20220324091153589

我們實現類也就是我們常說的實現AOP的兩種方式,使用cglib和jdk動態代理的方式。

我們簡要的介紹一下這兩種aop的原理。

動態代理步驟:
1.建立一個實現介面InvocationHandler的類,它必須實現invoke方法
2.建立被代理的類以及介面
3.通過Proxy的靜態方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)建立一個代理
4.通過代理呼叫invoke方法

我們分別看下這兩種實現方式。

JDK的方式

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   // 1.拿到要被代理物件的所有介面
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   // 2.通過classLoader、介面、InvocationHandler實現類,來獲取到代理物件
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

getproxy這個方法已經建立了代理物件,接下來就要執行實現類的invoke方法了。

顯而易見,我們這上一步將環繞通知都已經包裝好了,這一步代理物件也已經建立好了,接下來肯定就是要處理我們環繞通知裡面的方法了。

//當我們呼叫了被 AOP 代理的方法時,使用 JDK 動態代理會走到 JdkDynamicAopProxy#invoke 方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   // 1.advised就是proxyFactory,而targetSource持有被代理物件的引用
   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.
         // 目標不實現equals(Object)方法本身。
         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.
         // 只有getDecoratedClass()宣告 - > dispatch到代理配置。
         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...
         // ProxyConfig上的服務呼叫與代理配置..
         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.
      // 2.拿到我們被代理的物件例項
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      // 3.獲取攔截器鏈:例如使用@Around註解時會找到AspectJAroundAdvice,還有ExposeInvocationInterceptor
      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.
      // 4.檢查我們是否有任何攔截器(advice)。 如果沒有,直接反射呼叫目標,並避免建立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.
         // 5.不存在攔截器鏈,則直接進行反射呼叫
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         // 6.如果存在攔截器,則建立一個ReflectiveMethodInvocation:代理物件、被代理物件、方法、引數、
         // 被代理物件的Class、攔截器鏈作為引數建立ReflectiveMethodInvocation
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         // 7.觸發ReflectiveMethodInvocation的執行方法
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      // 8.必要時轉換返回值
      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);
      }
   }
}

cglib方式

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
   }

   try {
      // 1.拿到要代理目標類
      Class<?> rootClass = this.advised.getTargetClass();
      Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

      Class<?> proxySuperClass = rootClass;
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            // 將父類的介面也新增到advised的interfaces屬性
            this.advised.addInterface(additionalInterface);
         }
      }

      // Validate the class, writing log messages as necessary.
      // 2.校驗proxySuperClass,主要是校驗方法是否用final修飾、跨ClassLoader的包可見方法,如果有將警告寫入日誌
      validateClassIfNecessary(proxySuperClass, classLoader);

      // Configure CGLIB Enhancer...
      // 3.建立和配置Cglib Enhancer
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      // superclass為被代理的目標類proxySuperClass,通過名字可以看出,生成的代理類實際上是繼承了被代理類
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      // 4.獲取所有要回撥的攔截器
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      // 在上面呼叫getCallbacks之後,此時僅填充fixedInterceptorMap
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate the proxy class and create a proxy instance.
      // 5.生成代理類並建立代理例項,返回代理例項
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException | IllegalArgumentException ex) {
      throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
            ": Common causes of this problem include using a final class or a non-visible class",
            ex);
   }
   catch (Throwable ex) {
      // TargetSource.getTarget() failed
      throw new AopConfigException("Unexpected AOP exception", ex);
   }
}

總結一下AOP的整個流程,在Spring的核心方法refresh()中,建立單例物件前會執行InstantiationAwareBeanPostProcessor 方法的實現類,類似於Spring的前置處理器。

在實現類中會先將環繞通知包裝好,後執行建立代理方法,執行前判斷是jdk動態代理還是cglib,在jdk動態代理中,處理我們的環繞通知,以執行切面方法時進行執行。

歷時三個月將Spring的IOC和AOP的原始碼解讀就結束了,如果讀者想完整的熟悉整個流程,可以看歷史文章一步步的揭開Spring的神祕面紗。

相關文章