2018-10-03

Spring aop 是通過(guò)代理實(shí)現(xiàn)的,代理有靜態(tài)代理,jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理,代理就像我們生活中的房產(chǎn)中介,你不直接與房主,銀行接觸,而是通過(guò)中介與他們溝通聯(lián)系。

代理的結(jié)構(gòu)如圖所示:

img

RealSubject 和 Proxy都實(shí)現(xiàn)了相同的接口Subject,Proxy持有RealSubject的引用,但Client 調(diào)用 request方法時(shí),Proxy將請(qǐng)求轉(zhuǎn)發(fā)給RealSubject,其中可以添加各種訪問(wèn)控制。

但是靜態(tài)代理有一個(gè)弊端,需要為每一個(gè)目標(biāo)類(lèi)創(chuàng)建一個(gè)代理類(lèi),如果需要代理的對(duì)象很多的話,就得編寫(xiě)相應(yīng)的代理類(lèi),于是jdk動(dòng)態(tài)代理出現(xiàn)了,它主要用了 java.lang.reflect.Proxy類(lèi)和java.lang.reflect.InvocationHandler接口。

我們先實(shí)現(xiàn)java.lang.reflect.InvocationHandler,添加需要的橫切邏輯


public class AccessControl implements InvocationHandler {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//調(diào)用前的處理

  System.out.println("調(diào)用前驗(yàn)證");

  Object obj  = method.invoke(proxy, args);

//調(diào)用后的處理

  System.out.println("調(diào)用后處理");

  return obj;

}

}

然后通過(guò)Proxy為不同的類(lèi)型生成相應(yīng)的代理對(duì)象。


Proxy.newProxyInstance(targertClass1.getClassLoader(), targertClass1.getInterfaces(),accessControl);

Proxy.newProxyInstance(targertClass2.getClassLoader(), targertClass2.getInterfaces(),accessControl);

不管targetClass有多少類(lèi)型,都可以通過(guò)Proxy生成具有相同訪問(wèn)控制accesControl的代理對(duì)象。

從上面示例可知jdk動(dòng)態(tài)代理需要被代理類(lèi)實(shí)現(xiàn)接口(Interface),對(duì)于沒(méi)有實(shí)現(xiàn)任何接口的目標(biāo)對(duì)象,我們就要另找方法了。默認(rèn)情況下,當(dāng)Spring發(fā)現(xiàn)目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)任何接口時(shí),會(huì)使用CGLIB,為目標(biāo)對(duì)象動(dòng)態(tài)生成代理對(duì)象,其實(shí)質(zhì)就是對(duì)目標(biāo)對(duì)象進(jìn)行繼承,生成子類(lèi),子類(lèi)覆蓋父類(lèi)的方法,在其中加入額外的訪問(wèn)控制,不過(guò)如果類(lèi)中的方法聲明為final的話,就不能對(duì)它進(jìn)行擴(kuò)展。

Spring 創(chuàng)建代理的秘密在DefaultAopProxyFactory 類(lèi)中可以找到:


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

  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 CglibProxyFactory.createCglibProxy(config);

  } else {

  return new JdkDynamicAopProxy(config);

  }

}

如果isOptimize()返回true,或者proxyTargetClass屬性為true,或者目標(biāo)對(duì)象沒(méi)有接口實(shí)現(xiàn),就采用cglib動(dòng)態(tài)代理,否則就用jdk動(dòng)態(tài)代理。再看看JdkDynamicAopProxy中的getProxy


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);

}

請(qǐng)看最后一行代碼,是否有似曾相識(shí)之感。

Spring aop 僅作用于方法,如果你想對(duì)構(gòu)造方法或字段作攔截處理,就要引入AspectJ,它支持在編譯期間織入橫切邏輯,提高運(yùn)行期間的性能,但在易用性和靈活性上不如Spring aop。值得注意的是,Spring中@AspectJ注解區(qū)別的切面也是基于Spring aop 的代理機(jī)制實(shí)現(xiàn)的,不要被這個(gè)名稱(chēng)混淆了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書(shū)筆記,整理的知識(shí)點(diǎn),也是為了防止忘記,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 12,465評(píng)論 6 86
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評(píng)論 19 139
  • 本文主要講實(shí)現(xiàn)AOP的 代理模式原理,以及靜態(tài)代理,動(dòng)態(tài)代理的區(qū)別和具體實(shí)現(xiàn)。 對(duì)SpringAOP的概念和使用,...
    _Zy閱讀 814評(píng)論 0 1
  • 序章 東迷之大陸的花又開(kāi)了,微風(fēng)中白色的花瓣輕輕擺動(dòng),把花香送去遠(yuǎn)方,遠(yuǎn)方的土地上神的身影漸漸遠(yuǎn)去,神所給予力量的...
    葫蘆菌閱讀 318評(píng)論 0 0
  • 我們從邁阿密坐灰狗大巴沿著美國(guó)1號(hào)公路駛離大陸,進(jìn)入了跨海之旅,奔向基韋斯特島。一連串被稱(chēng)作“佛羅里達(dá)鑰匙”(Fl...
    惠茹姐姐閱讀 1,675評(píng)論 4 17

友情鏈接更多精彩內(nèi)容