Spring AOP 實(shí)現(xiàn)原理 與CGLIb應(yīng)用

什么是Spring AOP

Spring AOP 是Spring的核心功能糜芳,因?yàn)镴ava是面向?qū)ο缶幊天酰嗟氖且粋€縱向的,但是遇到存在不存在關(guān)聯(lián)和繼承關(guān)系的橫向關(guān)系時峭竣,就無法處理塘辅。所以這時可以通過切入點(diǎn),將不相關(guān)的邏輯織入到當(dāng)前業(yè)務(wù)代碼中皆撩。

Spring AOP的類型

AOP的代理可分為

  • 靜態(tài)代理:編譯時增強(qiáng)扣墩,使用AOP框架提供的命令進(jìn)行編譯,從而在編譯階段生成AOP代理類扛吞。
  • 動態(tài)代理:運(yùn)行時增強(qiáng)呻惕,借助JDK動態(tài)代理、CGLIB在內(nèi)存中臨時生成AOP動態(tài)代理類滥比。

Spring 使用了同AspectJ 5 一樣的注解亚脆,但是并沒有 使用AspectJ編譯器和織入器(Weaver),底層依然使用的Spring AOP 來實(shí)現(xiàn)動態(tài)代理生成AOP。

使用Spring AOP 實(shí)現(xiàn)AOP

  • 啟用注解模式
<!-- 啟動 @AspectJ 支持 -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
  • 定義需要處理的Bean
// 使用 @Aspect 定義一個方面類
@Component 
public class Chinese
{ 
   public String sayHello(String name){ 
       System.out.println("-- 正在執(zhí)行 sayHello 方法 --"); 
       // 返回簡單的字符串
       return name + " Hello , Spring AOP"; 
   } 
// 定義一個 eat() 方法
   public void eat(String food){ 
      System.out.println("我正在吃 :"+ food); 
   } 
}
  • 切入增加方法:事務(wù)控制盲泛、日志記錄
  //定義一個切面
@Aspect
public class AfterReturnTest{
  //匹配包下所有的方法執(zhí)行為切入點(diǎn)
@AfterReturning(return="rvt",pointcut="execution(* cn.com.bluemoon.service.impl.*.*")
  public void log(Object rvt){
    System.out.println("獲取目標(biāo)方法返回值:"+ rvt);
    System.out.println("模擬日制記錄...");
  }
}

在程序中增加System.out.println(p.getClass());

代碼可以輸入p變量所引用對象的實(shí)現(xiàn)類濒持,再次執(zhí)行將看到代碼產(chǎn)生class org...**.Chinese$EnhancerByCgLib$$290441d2的輸出,這才是p變量所引用的對象的實(shí)現(xiàn)類寺滚,同時也是Spring AOP動態(tài)生成的AOP代理類柑营。

若將上面程序稍作修改:讓業(yè)務(wù)羅積累Chinese類實(shí)現(xiàn)一個任意接口例如:

public interface Person 
{ 
String sayHello(String name); 
void eat(String food); 
}

接下來Beantest類面向Person接口、而不是Chinese類編程村视。

public class BeanTest 
{ 
public static void main(String[] args) 
{ 
// 創(chuàng)建 Spring 容器
ApplicationContext ctx = new 
ClassPathXmlApplicationContext("bean.xml"); 
Person p = ctx.getBean("chinese" ,Person.class);
System.out.println(p.sayHello("張三")); 
p.eat("西瓜"); 
System.out.println(p.getClass()); 
} 
}

執(zhí)行輸出的將會是class$Proxy7官套,說明AOP代理由JDK動態(tài)代理生成。

Spring AOP 動態(tài)代理原則

類型 實(shí)現(xiàn)方式
CGLIB 目標(biāo)對象實(shí)現(xiàn)類沒有實(shí)現(xiàn)接口
JDK 目標(biāo)對象實(shí)現(xiàn)了接口

Spring AOP 原理

Spring AOP結(jié)構(gòu)圖

如圖所示: Spring AOP的代理是由Spring的Ioc容易負(fù)責(zé)生成蚁孔、管理奶赔,其依賴關(guān)系也由Ioc容器負(fù)責(zé)管理。因此勒虾,AOP代理可以直接使用容器中的其他bean實(shí)例座位目標(biāo)纺阔,這種關(guān)系可由IOC容器的依賴注入提供。
而我們需要做的是:

  • 定義普通業(yè)務(wù)組件
  • 定義切入點(diǎn)修然,一個切入點(diǎn)可能橫切多個業(yè)務(wù)組件
  • 定義增強(qiáng)處理(After笛钝、Before质况、Around),AOP框架為普通業(yè)務(wù)組件織入(weaver)處理動作玻靡。

CGLIB 生成代理類

CGLIB(Code Generation Library)即代碼生成庫结榄。可以在運(yùn)行時動態(tài)的生成某個類的自雷囤捻。

AroundAdivice.java : 攔截器實(shí)現(xiàn)類
public class AroundAdvice implements MethodInterceptor 
{ 
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)throws 
 java.lang.Throwable { 
  System.out.println("執(zhí)行目標(biāo)方法之前臼朗,模擬開始事務(wù) ..."); 
  // 執(zhí)行目標(biāo)方法,并保存目標(biāo)方法執(zhí)行后的返回值
  Object rvt = proxy.invokeSuper(target, new String[]{"被改變的參數(shù)"}); 
  System.out.println("執(zhí)行目標(biāo)方法之后蝎土,模擬結(jié)束事務(wù) ..."); 
  return rvt + " 新增的內(nèi)容"; 
  } 
}

它的作可以在調(diào)用目標(biāo)方法之前视哑、調(diào)用目標(biāo)方法之后織入增強(qiáng)處理。

ChineseProxyFactory.java:工作類
public class ChineseProxyFactory 
{ 
  public static Chinese getAuthInstance(){ 
    Enhancer en = new Enhancer(); 
    // 設(shè)置要代理的目標(biāo)類
    en.setSuperclass(Chinese.class);
    // 設(shè)置要代理的攔截器
    en.setCallback(new AroundAdvice());
    // 生成代理類的實(shí)例 
    return (Chinese)en.create();
  } 
}

通過Enhancer 將Chinese類作為目標(biāo)誊涯,以AroundAdvice對象作為ADvice挡毅,程序?qū)梢粋€Chinese的子類,這個子類就是CGLIB生成的代理類暴构,作為Chinese對象使用跪呈,但它增強(qiáng)了Chinese類的方法。

測試效果:

public class Main 
{ 
public static void main(String[] args) 
{ 
Chinese chin = ChineseProxyFactory.getAuthInstance(); 
System.out.println(chin.sayHello("孫悟空")); 
chin.eat("西瓜"); 
System.out.println(chin.getClass()); 
} 
}
-- 正在執(zhí)行 sayHello 方法 --

執(zhí)行目標(biāo)方法之后取逾,模擬結(jié)束事務(wù) ...

被改變的參數(shù) Hello , CGLIB 新增的內(nèi)容

執(zhí)行目標(biāo)方法之前耗绿,模擬開始事務(wù) ...

我正在吃 : 被改變的參數(shù)

執(zhí)行目標(biāo)方法之后,模擬結(jié)束事務(wù) ...

class lee.Chinese$$EnhancerByCGLIB$$4bd097d9

小結(jié)

AOP廣泛應(yīng)用于處理一些具有橫切性質(zhì)的系統(tǒng)級服務(wù)砾隅,AOP的出現(xiàn)是對OOP的補(bǔ)充误阻,它是的開發(fā)者能用更優(yōu)雅的方式處理具有橫切性質(zhì)的服務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琉用,一起剝皮案震驚了整個濱河市堕绩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邑时,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件特姐,死亡現(xiàn)場離奇詭異晶丘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)唐含,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門浅浮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捷枯,你說我怎么就攤上這事滚秩。” “怎么了淮捆?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵郁油,是天一觀的道長本股。 經(jīng)常有香客問我,道長桐腌,這世上最難降的妖魔是什么拄显? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮案站,結(jié)果婚禮上躬审,老公的妹妹穿的比我還像新娘。我一直安慰自己蟆盐,他們只是感情好承边,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著石挂,像睡著了一般博助。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上誊稚,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天翔始,我揣著相機(jī)與錄音,去河邊找鬼里伯。 笑死城瞎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疾瓮。 我是一名探鬼主播脖镀,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼狼电!你這毒婦竟也來了蜒灰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤肩碟,失蹤者是張志新(化名)和其女友劉穎强窖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體削祈,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翅溺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了髓抑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咙崎。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吨拍,靈堂內(nèi)的尸體忽然破棺而出褪猛,到底是詐尸還是另有隱情,我是刑警寧澤羹饰,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布伊滋,位于F島的核電站碳却,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏新啼。R本人自食惡果不足惜追城,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望燥撞。 院中可真熱鬧座柱,春花似錦、人聲如沸物舒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冠胯。三九已至火诸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荠察,已是汗流浹背置蜀。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悉盆,地道東北人盯荤。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像焕盟,于是被迫代替她去往敵國和親秋秤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理脚翘,服務(wù)發(fā)現(xiàn)灼卢,斷路器,智...
    卡卡羅2017閱讀 134,639評論 18 139
  • 本文主要講實(shí)現(xiàn)AOP的 代理模式原理来农,以及靜態(tài)代理鞋真,動態(tài)代理的區(qū)別和具體實(shí)現(xiàn)。 對SpringAOP的概念和使用沃于,...
    _Zy閱讀 748評論 0 1
  • IOC和DI是什么灿巧? Spring IOC 的理解,其初始化過程揽涮? BeanFactory 和 FactoryBe...
    justlpf閱讀 3,463評論 1 21
  • 什么是Spring Spring是一個開源的Java EE開發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,445評論 1 133
  • 中國有沒有哲學(xué)呢饿肺?我原來只知道中國有孔孟老莊蒋困,有百家爭鳴,中國的孔子學(xué)院遍地開花敬辣,卻沒有中國哲學(xué)的概念雪标。馮友蘭先生...
    明明如月還在閱讀 961評論 1 3