Spring 源碼分析(三) —— AOP(五)建立代理

建立代理

        代理的定義其實很是簡單,就是改變原來目標對象方法調用的運行軌跡。這種改變,首先會對這些方法進行攔截,從而爲這些方法提供工做空間,隨後在進行回調,從而完成 AOP 切面實現的一整個邏輯。java

        而建立代理是 Spring AOP 功能實現最核心的地方,通常而言 Spring AOP 動態生成代理有兩種方法:JDK 和 CGLIB。下面是具體時序圖:app

        經過時序圖的分析咱們知道她主要是由 AbstractAutoProxyCreator 類和 ProxyFactory 工廠類來完成的。下面咱們進行分析。ide


初始化操做

        建立代理工廠

        在獲取了全部對應 bean 的加強器後,即可以進行代理的建立了。        
函數

AbstractAutoProxyCreator.java
源碼分析

protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

   ProxyFactory proxyFactory = new ProxyFactory();
   // 獲取當前類中相關屬性
   proxyFactory.copyFrom(this);
   // 決定對給定的 bean 是否應該使用 targetClass 而不是他的接口代理,
   // 檢查 proxyTargeClass 設置以及 preserveTargetClass 屬性
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      // 加入加強器
      proxyFactory.addAdvisor(advisor);
   }
   // 設置要代理的類
   proxyFactory.setTargetSource(targetSource);
   // 定製代理
   customizeProxyFactory(proxyFactory);
   
   // 用來控制代理過程被配置以後,是否還容許修改通知。
   // 缺省值爲 false (即在代理被配置以後,不容許修改代理的配置)
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   return proxyFactory.getProxy(getProxyClassLoader());
}

        對於代理類的建立及處理,Spring 委託給了 ProxyFactory 去處理,而在此函數中主要是對 ProxyFactory 的初始化操做,進而對真正的建立代理作準備,這些初始化操做包括6個內容:(1)獲取當前類中的屬性。(2)添加代理接口。(3)封裝 Advisor 並加入到 ProxyFactory 中。(4)設置要代理的類。(5)固然在 Spring 中還爲子類提供了定製的函數 customizeProxyFactory,子類能夠在此函數中對 ProxyFactory 的進一步封裝。(6)進行獲取代理操做。
性能


        封裝邏輯

        其中,封裝 Advisor 並加入到 ProxyFactory 中以及建立代理是最爲繁瑣的兩個過程,能夠經過 ProxyFactory 提供 addAdvisor 方法直接將通知器置如代理建立工廠中,可是將攔截器封裝爲通知器仍是須要必定邏輯的。
優化

AbstractAutoProxyCreator.javaui

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
   // 解析註冊的全部 interceptorName
   Advisor[] commonInterceptors = resolveInterceptorNames();

   List<Object> allInterceptors = new ArrayList<Object>();
   if (specificInterceptors != null) {
      // 加入攔截器
      allInterceptors.addAll(Arrays.asList(specificInterceptors));
      if (commonInterceptors != null) {
         if (this.applyCommonInterceptorsFirst) {
            allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
         }
         else {
            allInterceptors.addAll(Arrays.asList(commonInterceptors));
         }
      }
   }
   if (logger.isDebugEnabled()) {
      int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
      int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
      logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
            " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
   }

   Advisor[] advisors = new Advisor[allInterceptors.size()];
   for (int i = 0; i < allInterceptors.size(); i++) {
      // 攔截器進行封裝轉化爲 Advisor
      advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
   }
   return advisors;
}

DefaultAdvisorAdapterRegistry.javathis

@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
   // 若是要封裝的對象自己就是 Advisor 類型的那麼無需再作過多處理
   if (adviceObject instanceof Advisor) {
      return (Advisor) adviceObject;
   }
   // 由於此封裝方法只對 Advisor 與 Advice 兩種類型的數據有效
   if (!(adviceObject instanceof Advice)) {
      throw new UnknownAdviceTypeException(adviceObject);
   }
   Advice advice = (Advice) adviceObject;
   if (advice instanceof MethodInterceptor) {
      // 若是是 MethodInterceptor 類型則使用 DefaultPointcutAdvisor 封裝
      return new DefaultPointcutAdvisor(advice);
   }
   // 若是存在 Advisor 的適配器那麼也須要進行封裝
   for (AdvisorAdapter adapter : this.adapters) {
      // Check that it is supported.
      if (adapter.supportsAdvice(advice)) {
         return new DefaultPointcutAdvisor(advice);
      }
   }
   throw new UnknownAdviceTypeException(advice);
}

        因爲 Spring 中涉及過多的攔截器、通知器、加強方法等方式來對邏輯進行加強,因此很是有必要統一封裝成 Advisor 來進行代理的建立,完成了加強的封裝過程,那麼解析最重要的一步就是代理的建立與獲取了。
lua

AspectJProxyFactory.java

public <T> T getProxy(ClassLoader classLoader) {
   return (T) createAopProxy().getProxy(classLoader);
}


代理生成

        建立代理

        咱們接着上面的例子繼續進行分析。

ProxyCreatorSupport.java

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // 建立代理
   return getAopProxyFactory().createAopProxy(this);
}

        createAopProxy 方法封裝在 AopProxyFactory 接口中,經過對接口繼承關係的跟蹤,最終在 DefaultAopFactory中找到了其實現方法。

DefaultAopFactory.java

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   // 這裏判斷是使用 JDKProxy 的實現或者 CGLIBProxy 的實現
   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.");
      }
      if (targetClass.isInterface()) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

        到此已經完成了代理建立。而源碼中提到的 JDK 動態代理 和 CGLIB 字節碼生成代理筆者會在隨後進行介紹,這裏須要注意的是if中的三個判斷條件:(1)optimize:用來控制經過CGLIB建立的代理是否使用激進的優化策略。除非徹底瞭解AOP。不然不推薦。目前這個屬性也僅僅用於 CGLIB。(2)proxyTargetClass:這個屬性爲 true 時,目標類自己本代理而不是目標類的接口。若是這個屬性值被設爲 true,CGLIB 代理將被建立,設置方式:<aop:aspectj-autoproxy proxy-target-class="true"/>。(3)hasNoUserSuppliedProxyInterfaces:是否存在代理接口。


        建立代理的方法

        Spring AOP 內動態生成代理有兩種方法:JDK 和 CGLIB。通常狀況下,若是目標對象實現了接口,默認狀況下會採用 JDK 動態代理實現 AOP。若是目標對象實現了接口,能夠強制使用 CGLIB 實現 AOP。若是目標對象沒有實現接口,必須採用 CGLIB,Spring 會自動在 JDK動態代理和 CGLIB 之間轉化。並且,JDK 動態代理只能對實現了接口的類生成代理,而不能針對類。CGLIB是針對類實現代理的,但主要是對指定的類生成一個子類,覆蓋其中的方法,是繼承實現,因此該類或方法最好不要聲明成 final。

        這裏須要特別注意的是 AopProxy 接口,經過上面的代碼咱們知道了,AopProxy 纔是生成代理的主要位置。而前面看到的 ProxyFactory 在 AopProxy 代理對象和IOC容器配置之間僅僅起一個橋樑做用。AopProxy 代理對象能夠由 JDK 或 CGLIB 來生成,而下面是他們的層次關係:


        JDK 動態代理

        在對於 JDK 代理的使用中,JDK 動態代理的實現類 JdkDynamicAopProxy,而 JdkDynamicAopProxy 類最爲核心的是 InvocationHandler 接口。而在 JdkDynamicAopProxy 類的方法裏較爲重要的有三個:構造函數、invoke 方法和 getProxy 方法。下面我就一個個的進行分析:

JdkDynamicAopProxy.java

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
   Assert.notNull(config, "AdvisedSupport must not be null");
   if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
      throw new AopConfigException("No advisors and no TargetSource specified");
   }
   this.advised = config;
}

        從源碼咱們能夠看出,構造函數主要適用於傳值。

JdkDynamicAopProxy.java

@Override
public Object getProxy(ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
   }
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

        而 getProxy 方法則是用於獲取生成的代理對象的,是必不可少的方法。

JdkDynamicAopProxy.java

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

   TargetSource targetSource = this.advised.targetSource;
   Class<?> targetClass = null;
   Object target = null;

   try {
      // equals 方法的處理
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         return equals(args[0]);
      }
      // hash 方法的處理
      if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         return hashCode();
      }
      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;
      }

      target = targetSource.getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }

      // 獲取當前方法的攔截器
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      if (chain.isEmpty()) {
         // 若是沒有發現任何攔截器那麼直接調入切點方法
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
      }
      else {
         // 將攔截器封裝在 ReflectiveMethodInvocation
         // 以便於使用期 proceed 進行連接表用攔截器
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // 執行攔截器鏈
         retVal = invocation.proceed();
      }

      // 返回結果
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         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()) {
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

ReflectiveMethodInvocation.java

@Override
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) {
      // 動態匹配
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // 不匹配則不執行攔截器
         return proceed();
      }
   }
   else {
      // 將 this 做爲參數傳遞以保證檔期實例中調用鏈的執行
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

        經過源碼咱們知道,invoke 方法是其核心邏輯實現的地方。其主要的工做就是建立一個攔截器鏈,而後使用 ReflectiveMethodInvocation 類對鏈進行封裝,最後經過 proceed 方法對攔截器進行逐個調用,而 proceed 方法負責實現方法前調用以及後置調用的邏輯處理,而後將工做委託給各個加強器,在加強器內部實現具體邏輯。


        CGLIBProxy 字節碼生成代理

        CGLIB 是一個強大的高性能的代碼生成包。Spring AOP 中完成 CGLIB 代理是託付給 CglibAopProxy 類來實現的,而也動態代理類似 getProxy 方法是這個類的主要入口。

CglibAopProxy.java

@Override
public Object getProxy(ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
   }

   try {
      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) {
            this.advised.addInterface(additionalInterface);
         }
      }

      // 驗證 Class
      validateClassIfNecessary(proxySuperClass, classLoader);

      // 建立及配置 Enhancer 
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));

      // 設置攔截器
      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
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // 生成代理類以及建立代理
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException ex) {
      throw new AopConfigException("Could not generate CGLIB subclass of class [" +
            this.advised.getTargetClass() + "]: " +
            "Common causes of this problem include using a final class or a non-visible class",
            ex);
   }
   catch (IllegalArgumentException ex) {
      throw new AopConfigException("Could not generate CGLIB subclass of class [" +
            this.advised.getTargetClass() + "]: " +
            "Common causes of this problem include using a final class or a non-visible class",
            ex);
   }
   catch (Exception ex) {
      // TargetSource.getTarget() failed
      throw new AopConfigException("Unexpected AOP exception", ex);
   }
}

        CGLIB 的實現最重要的就是 Enhancer。以上函數完整地闡述了建立 Spring 的 Enhancer 過程,這裏值得注意的是設置攔截器鏈 getCallbacks 方法。

CglibAopProxy.java

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
   // 對於 expose-proxy 屬性的處理
   boolean exposeProxy = this.advised.isExposeProxy();
   boolean isFrozen = this.advised.isFrozen();
   boolean isStatic = this.advised.getTargetSource().isStatic();

   // 將攔截器封裝在 DynamicAdvisedInterceptor 中
   Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

   // Choose a "straight to target" interceptor. (used for calls that are
   // unadvised but can return this). May be required to expose the proxy.
   Callback targetInterceptor;
   if (exposeProxy) {
      targetInterceptor = isStatic ?
            new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
            new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
   }
   else {
      targetInterceptor = isStatic ?
            new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
            new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
   }

   // Choose a "direct to target" dispatcher (used for
   // unadvised calls to static targets that cannot return this).
   Callback targetDispatcher = isStatic ?
         new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

   Callback[] mainCallbacks = new Callback[]{
      aopInterceptor, // 將攔截器鏈加入 Callback 中
      targetInterceptor, // invoke target without considering advice, if optimized
      new SerializableNoOp(), // no override for methods mapped to this
      targetDispatcher, this.advisedDispatcher,
      new EqualsInterceptor(this.advised),
      new HashCodeInterceptor(this.advised)
   };

   Callback[] callbacks;

   // If the target is a static one and the advice chain is frozen,
   // then we can make some optimisations by sending the AOP calls
   // direct to the target using the fixed chain for that method.
   if (isStatic && isFrozen) {
      Method[] methods = rootClass.getMethods();
      Callback[] fixedCallbacks = new Callback[methods.length];
      this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

      // TODO: small memory optimisation here (can skip creation for methods with no advice)
      for (int x = 0; x < methods.length; x++) {
         List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
         fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
               chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
         this.fixedInterceptorMap.put(methods[x].toString(), x);
      }

      // Now copy both the callbacks from mainCallbacks
      // and fixedCallbacks into the callbacks array.
      callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
      System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
      System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
      this.fixedInterceptorOffset = mainCallbacks.length;
   }
   else {
      callbacks = mainCallbacks;
   }
   return callbacks;
}

        至此,Spring 源碼分析部分就完了,固然這僅僅是他衆多實現中的一種。  

        


——水門(2016年3月於杭州

相關文章
相關標籤/搜索