Spring AOP(七)細(xì)究 CglibAopProxy 類

接著上一篇 Spring AOP(六)細(xì)究 JdkDynamicAopProxy 類 ,我們來繼續(xù)分析 Spring 中 CGLIB 代理對象的生成和如何對方法進(jìn)行增強(qiáng)處理的邏輯烈钞。

回到 DefaultAopProxyFactory 類中的 createAopProxy 方法多矮,我們發(fā)現(xiàn)有兩個 AOP 代理類稻薇,除了 JdkDynamicAopProxy 類還有 ObjenesisCglibAopProxy 類兔乞。

為了方便閱讀半夷,把上文中的 createAopProxy 方法的代碼清單再次貼出來机杜。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  // config.isOptimize() 這個屬性沒有研究過
  // 滿足下面三個條件的任意一個
  // 1. 如果 optimize 屬性為 ture 
  // 2. 或者 proxyTargetClass 屬性為 ture
  // 3. 被代理類沒有可代理的接口
  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.");
    }
    // 如果被代理類的類型是接口客情,或者被代理類是 JDK 動態(tài)代理生成的代理類其弊,則使用 JDK 動態(tài)代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      return new JdkDynamicAopProxy(config);
    }
    
    // 使用 CGLIB 動態(tài)代理
    return new ObjenesisCglibAopProxy(config);
  }
  else {
    //  使用 JDK 動態(tài)代理
    return new JdkDynamicAopProxy(config);
  }
}

源碼分析

下面我們就從 ObjenesisCglibAopProxy 類開始分析,ObjenesisCglibAopProxy 類的代碼清單如下所示膀斋。

class ObjenesisCglibAopProxy extends CglibAopProxy {

  private static final SpringObjenesis objenesis = new SpringObjenesis();
  
  public ObjenesisCglibAopProxy(AdvisedSupport config) {
    super(config);
  }

  @Override
  protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
      // 通過 Objenesis 技術(shù)實(shí)例化代理對象
  }
  
}

可以看到 ObjenesisCglibAopProxy 中就只有實(shí)例化代理對象的方法梭伐,getProxy() 方法在其父類 CglibAopProxy 類中定義,代碼清單如下所示仰担。

public Object getProxy() {
  return getProxy(null);
}

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

  try {
    Class<?> rootClass = this.advised.getTargetClass();
    Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

    // CGLIB 代理類通過繼承被代理類實(shí)現(xiàn)動態(tài)代理
    // 1. 獲得需要被代理的的類
    Class<?> proxySuperClass = rootClass;
    if (ClassUtils.isCglibProxyClass(rootClass)) {
      // 如果被代理類已經(jīng)是被 CGLIB 代理過的了舶沛,則代理其父類,避免出現(xiàn) java.lang.ClassFormatError: Duplicate method name "newInstance" 異常
      // 舉個例子:rootClass 是 【Spring AOP (三) CGLIB 動態(tài)代理】Service 的代理類 Service$$EnhancerByCGLIB$$bdabbd96 卷要,那么這里的 proxySuperClass 就是 Service 
      proxySuperClass = rootClass.getSuperclass();
      Class<?>[] additionalInterfaces = rootClass.getInterfaces();
      for (Class<?> additionalInterface : additionalInterfaces) {
        // 添加代理類實(shí)現(xiàn)的相關(guān)接口,addInterface 方法中會對接口做去重處理
        this.advised.addInterface(additionalInterface);
      }
    }

    // Validate the class, writing log messages as necessary.
    validateClassIfNecessary(proxySuperClass, classLoader);

    // 2. 配置 CGLIB Enhancer愉耙,還記得 【Spring AOP (三) CGLIB 動態(tài)代理】 中通過 enhancer  創(chuàng)建代理類的例子嗎?
    Enhancer enhancer = createEnhancer();
    if (classLoader != null) {
      enhancer.setClassLoader(classLoader);
      if (classLoader instanceof SmartClassLoader &&
          ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
        enhancer.setUseCache(false);
      }
    }
    // 設(shè)置被代理類為代理類的父類
    enhancer.setSuperclass(proxySuperClass);
    // 設(shè)置代理類需要實(shí)現(xiàn)的接口
    // AopProxyUtils.completeProxiedInterfaces 方法在 【Spring AOP(六)細(xì)研JdkDynamicAopProxy類】中有詳細(xì)描述拌滋,這里就不贅述
    enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    // 設(shè)置 CGLIB 代理類的命名策略
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    // 設(shè)置 CGLIB 代理類字節(jié)碼的默認(rèn)生成策略
    enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

    // 3. 獲取到生成代理類所需的所有 Callback
    Callback[] callbacks = getCallbacks(rootClass);
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
      types[x] = callbacks[x].getClass();
    }
    // 一個 method 只能被一個 Callback 增強(qiáng)處理
    // 4. 存在超過一個 Callback 的情況下朴沿,就需要設(shè)置 CallbackFilter,用來分配一個 method 由哪個 Callback 增強(qiáng)處理
    enhancer.setCallbackFilter(new ProxyCallbackFilter(
        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);

    // 5. 生成代理類并創(chuàng)建代理類實(shí)例败砂。
    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);
  }
}

接下來分析在 getProxy 方法中一些需要關(guān)注的地方赌渣。

SpringNamingPolicy 類的代碼清單如下所示。

public class SpringNamingPolicy extends DefaultNamingPolicy {

  public static final SpringNamingPolicy INSTANCE = new SpringNamingPolicy();

  @Override
  protected String getTag() {
    // DefaultNamingPolicy 中返回 ByCGLIB昌犹,
    // 所有通過類名我們就可以知道是 Spring 生成的代理類坚芜,還是 CGLIB 原生生成的代理類
    return "BySpringCGLIB";
  }

}

DefaultNamingPolicy 類在 Spring AOP (三) CGLIB 動態(tài)代理 一文中已經(jīng)討論過了,這里就不再贅述斜姥。

getCallbacks 的代碼清單如下所示鸿竖。

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
  // Parameters used for optimization choices...
  boolean exposeProxy = this.advised.isExposeProxy();
  boolean isFrozen = this.advised.isFrozen();
  boolean isStatic = this.advised.getTargetSource().isStatic();

  // 定義一個用于 AOP 調(diào)用的 MethodInterceptor (DynamicAdvisedInterceptor)
  Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

  // targetInterceptor 是不對方法做增強(qiáng)處理的 MethodInterceptor,直接在 intercept 調(diào)用目標(biāo)對象的目標(biāo)方法
  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()));
  }

  // 不需要返回 this 的 method疾渴,可以用 StaticDispatcher 進(jìn)行代理千贯,即直接通過 target 對象調(diào)用目標(biāo)方法
  Callback targetDispatcher = (isStatic ?
      new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

  Callback[] mainCallbacks = new Callback[] {
      aopInterceptor,  // for normal advice
      targetInterceptor,  // invoke target without considering advice, if optimized
      // 不需要增強(qiáng)的方法
      new SerializableNoOp(),  
      targetDispatcher, 
      // 通過 advised 直接調(diào)用 Advised 接口的方法
      this.advisedDispatcher,
      // 專門用來處理 equals 方法的攔截器,和 JdkDynamicAopProxy 類似
      new EqualsInterceptor(this.advised),
      // 專門用來處理 equals 方法的攔截器搞坝,和 JdkDynamicAopProxy 類似
      new HashCodeInterceptor(this.advised)
  };

  Callback[] callbacks;

  // 忽略了 isStatic && isFrozen 條件的邏輯處理
    callbacks = mainCallbacks;
  return callbacks;
}

ProxyCallbackFilter 類的代碼清單如下所示,我們主要關(guān)注 accept 方法魁袜。

// CGLIB callback 數(shù)組索引常量
private static final int AOP_PROXY = 0;  // DynamicAdvisedInterceptor
private static final int INVOKE_TARGET = 1; // StaticUnadvisedExposedInterceptor或 DynamicUnadvisedExposedInterceptor
private static final int NO_OVERRIDE = 2; // SerializableNoOp
private static final int DISPATCH_TARGET = 3; // StaticDispatcher
private static final int DISPATCH_ADVISED = 4; // AdvisedDispatcher
private static final int INVOKE_EQUALS = 5; // EqualsInterceptor
private static final int INVOKE_HASHCODE = 6; // HashCodeInterceptor

private static class ProxyCallbackFilter implements CallbackFilter {

    private final AdvisedSupport advised;
    /**
     * 實(shí)現(xiàn) CallbackFilter.accept() 以返回我們需要的 Callbacks 數(shù)組中的 index 值桩撮。
     */
    @Override
    public int accept(Method method) {
    
      // finalize 方法不需要代理類重寫
      if (AopUtils.isFinalizeMethod(method)) {
        return NO_OVERRIDE;
      }
      
      // Advised 接口的方法由 AdvisedDispatcher 增強(qiáng)處理,即直接調(diào)用 advised 中的對應(yīng)方法
      if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
          method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        return DISPATCH_ADVISED;
      }
      // equals 方法由 EqualsInterceptor 代理
      if (AopUtils.isEqualsMethod(method)) {
        return INVOKE_EQUALS;
      }
      // hashCode 方法由 HashCodeInterceptor 代理
      if (AopUtils.isHashCodeMethod(method)) {
        return INVOKE_HASHCODE;
      }
      Class<?> targetClass = this.advised.getTargetClass();
      List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      
      // chain 不為空峰弹,表示當(dāng)前 method 需要被增強(qiáng)處理
      boolean haveAdvice = !chain.isEmpty();
      boolean exposeProxy = this.advised.isExposeProxy();
      boolean isStatic = this.advised.getTargetSource().isStatic();
      boolean isFrozen = this.advised.isFrozen();
      if (haveAdvice || !isFrozen) {
        // 如果公開代理店量,讓其在整個攔截器責(zé)任鏈種可見,則必須使用 AOP_PROXY鞠呈,即 DynamicAdvisedInterceptor
        if (exposeProxy) {
          return AOP_PROXY;
        }
        String key = method.toString();
        // 檢查我們是否有固定攔截器來增強(qiáng)當(dāng)前 method融师。
        if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
          // 通過 FixedChainStaticTargetInterceptor 對攔截器做特定的優(yōu)化處理
          int index = this.fixedInterceptorMap.get(key);
          return (index + this.fixedInterceptorOffset);
        }
        else {
          // 否則使用 AOP_PROXY,即 DynamicAdvisedInterceptor
          return AOP_PROXY;
        }
      }
      else {
        // 如果需要暴露代理對象蚁吝,或者 target 對象是可變的旱爆,則通過 StaticUnadvisedExposedInterceptor 代理
        if (exposeProxy || !isStatic) {
          return INVOKE_TARGET;
        }
        
        // 如果當(dāng)前方法的返回類型是目標(biāo)對象的類型,則通過 StaticUnadvisedExposedInterceptor 代理
        Class<?> returnType = method.getReturnType();
        if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
          return INVOKE_TARGET;
        }
        else {
          // 否則窘茁,通過 StaticDispatcher 進(jìn)行代理
          return DISPATCH_TARGET;
        }
      }
    }
  }

然后我們重點(diǎn)關(guān)注 Spring AOP 的實(shí)現(xiàn)邏輯怀伦,在 DynamicAdvisedInterceptor 類中可以看到完整的代碼清單。

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

  private final AdvisedSupport advised;

  public DynamicAdvisedInterceptor(AdvisedSupport advised) {
    this.advised = advised;
  }

  @Override
  @Nullable
  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    TargetSource targetSource = this.advised.getTargetSource();
    try {
      if (this.advised.exposeProxy) {
        // 如果需要在攔截器暴露 proxy 對象山林,則把 proxy 對象添加到 ThreadLocal 中
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
      }
       // 獲取目標(biāo)對象和目標(biāo)對象類型
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      
       // 獲取此方法的攔截器鏈房待,這個方法在【Spring AOP(六)細(xì)研JdkDynamicAopProxy類】種已經(jīng)討論過了,這里就不贅述了
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      
      // 如果攔截器集合為空,說明當(dāng)前 method 不需要被增強(qiáng)桑孩,則通過 methodProxy 直接調(diào)用目標(biāo)對象上的方法
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
        // 創(chuàng)建 CglibMethodInvocation拜鹤,用來管理方法攔截器責(zé)任鏈
        // 通過 proceed 方法驅(qū)動攔截器責(zé)任鏈的運(yùn)行,并獲取到返回值流椒。
        retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
    }
    finally {
      if (target != null && !targetSource.isStatic()) {
        targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
        // 把第一次調(diào)用 setCurrentProxy 返回的對象敏簿,重新設(shè)置到 ThreadLocal 中
        AopContext.setCurrentProxy(oldProxy);
      }
    }
  }
}

可以看到 DynamicAdvisedInterceptor 類中的 intercept 方法和 JdkDynamicAopProxy 類的 invoke 方法十分類似。

最后镣隶,我們再來看下 CglibMethodInvocation 類的詳細(xì)代碼清單极谊。

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

  @Nullable
  private final MethodProxy methodProxy;

  public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
      Object[] arguments, @Nullable Class<?> targetClass,
      List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

    super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

    // 僅對非 Object 類的方法使用 methodProxy 進(jìn)行調(diào)用,詳見 invokeJoinpoint() 方法
    this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
        method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
        !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
        methodProxy : null);
  }

  /**
   * 重寫 ReflectiveMethodInvocation 中通過反射調(diào)用目標(biāo)方法的邏輯
   */
  @Override
  protected Object invokeJoinpoint() throws Throwable {
    if (this.methodProxy != null) {
      return this.methodProxy.invoke(this.target, this.arguments);
    }
    else {
      return super.invokeJoinpoint();
    }
  }
}

CglibMethodInvocation 類繼承了 ReflectiveMethodInvocation 類安岂,并且僅重寫了其 invokeJoinpoint() 方法轻猖,而 proceed 方法在 Spring AOP(六)細(xì)究 JdkDynamicAopProxy 類 中已經(jīng)詳細(xì)講解,所以這里就不再贅述域那。

至此咙边,Spring 中的 CGLIB AOP 代理 就基本說完了。

(正文完)

擴(kuò)展閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末次员,一起剝皮案震驚了整個濱河市败许,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淑蔚,老刑警劉巖市殷,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異刹衫,居然都是意外死亡醋寝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門带迟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來音羞,“玉大人,你說我怎么就攤上這事仓犬⌒岽拢” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵搀继,是天一觀的道長窘面。 經(jīng)常有香客問我,道長律歼,這世上最難降的妖魔是什么民镜? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮险毁,結(jié)果婚禮上制圈,老公的妹妹穿的比我還像新娘们童。我一直安慰自己,他們只是感情好鲸鹦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布慧库。 她就那樣靜靜地躺著,像睡著了一般馋嗜。 火紅的嫁衣襯著肌膚如雪齐板。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天葛菇,我揣著相機(jī)與錄音甘磨,去河邊找鬼。 笑死眯停,一個胖子當(dāng)著我的面吹牛济舆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莺债,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼滋觉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了齐邦?” 一聲冷哼從身側(cè)響起椎侠,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎措拇,沒想到半個月后我纪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丐吓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年宣羊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汰蜘。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖之宿,靈堂內(nèi)的尸體忽然破棺而出族操,到底是詐尸還是另有隱情,我是刑警寧澤比被,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布色难,位于F島的核電站,受9級特大地震影響等缀,放射性物質(zhì)發(fā)生泄漏枷莉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一尺迂、第九天 我趴在偏房一處隱蔽的房頂上張望笤妙。 院中可真熱鬧冒掌,春花似錦、人聲如沸蹲盘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽召衔。三九已至铃诬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苍凛,已是汗流浹背趣席。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留醇蝴,地道東北人宣肚。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像哑蔫,于是被迫代替她去往敵國和親钉寝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容