AOP奇技淫巧

image

一盹兢、AOP的基本概念:

1瘦赫、什么是aop:

AOP(Aspect Oriented Programming)稱為面向切面編程,在程序開發(fā)中主要用來解決一些系統(tǒng)層面上的問題蛤迎,比如日志,事務(wù)含友,權(quán)限等待替裆,Struts2的攔截器設(shè)計就是基于AOP的思想,是個比較經(jīng)典的例子窘问。

在不改變原有的邏輯的基礎(chǔ)上辆童,增加一些額外的功能。代理也是這個功能惠赫,讀寫分離也能用aop來做把鉴。

AOP可以說是OOP(Object Oriented Programming,面向?qū)ο缶幊蹋┑难a充和完善。OOP引入封裝庭砍、繼承场晶、多態(tài)等概念來建立一種對象層次結(jié)構(gòu),用于模擬公共行為的一個集合怠缸。不過OOP允許開發(fā)者定義縱向的關(guān)系诗轻,但并不適合定義橫向的關(guān)系,例如日志功能揭北。日志代碼往往橫向地散布在所有對象層次中扳炬,而與它對應(yīng)的對象的核心功能毫無關(guān)系對于其他類型的代碼,如安全性搔体、異常處理和透明的持續(xù)性也都是如此恨樟,這種散布在各處的無關(guān)的代碼被稱為橫切(cross cutting),在OOP設(shè)計中疚俱,它導(dǎo)致了大量代碼的重復(fù)劝术,而不利于各個模塊的重用。

AOP技術(shù)恰恰相反计螺,它利用一種稱為"橫切"的技術(shù)夯尽,剖解開封裝的對象內(nèi)部,并將那些影響了多個類的公共行為封裝到一個可重用模塊登馒,并將其命名為"Aspect"匙握,即切面。所謂"切面"陈轿,簡單說就是那些與業(yè)務(wù)無關(guān)圈纺,卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼麦射,降低模塊之間的耦合度蛾娶,并有利于未來的可操作性和可維護性。

使用"橫切"技術(shù)潜秋,AOP把軟件系統(tǒng)分為兩個部分:核心關(guān)注點和橫切關(guān)注點蛔琅。業(yè)務(wù)處理的主要流程是核心關(guān)注點,與之關(guān)系不大的部分是橫切關(guān)注點峻呛。橫切關(guān)注點的一個特點是罗售,他們經(jīng)常發(fā)生在核心關(guān)注點的多處,而各處基本相似钩述,比如權(quán)限認證寨躁、日志、事物牙勘。AOP的作用在于分離系統(tǒng)中的各種關(guān)注點职恳,將核心關(guān)注點和橫切關(guān)注點分離開來。

2、AOP的相關(guān)概念:

(1)橫切關(guān)注點:對哪些方法進行攔截放钦,攔截后怎么處理色徘,這些關(guān)注點稱之為橫切關(guān)注點

(2)Aspect(切面):通常是一個類,里面可以定義切入點和通知

(3)JointPoint(連接點):程序執(zhí)行過程中明確的點最筒,一般是方法的調(diào)用贺氓。被攔截到的點,因為Spring只支持方法類型的連接點床蜘,所以在Spring中連接點指的就是被攔截到的方法辙培,實際上連接點還可以是字段或者構(gòu)造器

(4)Advice(通知):AOP在特定的切入點上執(zhí)行的增強處理,有before(前置),after(后置),afterReturning(最終),afterThrowing(異常),around(環(huán)繞)

(5)Pointcut(切入點):就是帶有通知的連接點邢锯,在程序中主要體現(xiàn)為書寫切入點表達式

(6)weave(織入):將切面應(yīng)用到目標對象并導(dǎo)致代理對象創(chuàng)建的過程

(7)introduction(引入):在不修改代碼的前提下扬蕊,引入可以在運行期為類動態(tài)地添加一些方法或字段

(8)AOP代理(AOP Proxy):AOP框架創(chuàng)建的對象,代理就是目標對象的加強丹擎。Spring中的AOP代理可以使JDK動態(tài)代理尾抑,也可以是CGLIB代理,前者基于接口蒂培,后者基于子類

(9)目標對象(Target Object): 包含連接點的對象再愈。也被稱作被通知或被代理對象。POJO

3护戳、Advice通知類型介紹:

(1)Before:在目標方法被調(diào)用之前做增強處理,@Before只需要指定切入點表達式即可

(2)AfterReturning:在目標方法正常完成后做增強,@AfterReturning除了指定切入點表達式后翎冲,還可以指定一個返回值形參名returning,代表目標方法的返回值

(3)AfterThrowing:主要用來處理程序中未處理的異常,@AfterThrowing除了指定切入點表達式后,還可以指定一個throwing的返回值形參名,可以通過該形參名

來訪問目標方法中所拋出的異常對象

(4)After:在目標方法完成之后做增強媳荒,無論目標方法時候成功完成抗悍。@After可以指定一個切入點表達式

(5)Around:環(huán)繞通知,在目標方法完成前后做增強處理,環(huán)繞通知是最重要的通知類型,像事務(wù),日志等都是環(huán)繞通知,注意編程中核心是一個ProceedingJoinPoint

4、AOP使用場景:

Authentication 權(quán)限

Caching 緩存

Context passing 內(nèi)容傳遞

Error handling 錯誤處理

Lazy loading 懶加載

Debugging  調(diào)試

logging, tracing, profiling and monitoring 記錄跟蹤 優(yōu)化 校準

Performance optimization 性能優(yōu)化

Persistence  持久化

Resource pooling 資源池

Synchronization 同步

Transactions 事務(wù)

二钳枕、你們認為的AOP 應(yīng)該是這樣的

對沒錯 缴渊,這是AOP 最常用的方式,作為日志處理鱼炒、異常處理衔沼、參數(shù)校驗 。

三昔瞧、我要說的AOP 長這樣

先描述下業(yè)務(wù)場景:對于 業(yè)務(wù)類型的訂單接口:我們可以通過數(shù)據(jù)校驗避免指蚁,訂單數(shù)據(jù)重復(fù)提交(例如:開始、結(jié)束硬爆、拒絕訂單) 但是對于 新建訂單 是無法通過 校驗實現(xiàn)的。 為了避免重復(fù)數(shù)據(jù)擎鸠,最好的就是引入鎖機制處理缀磕。但問題來了,又不是所有的接口都需要鎖,只是對特定的接口需要添加鎖袜蚕。添加鎖肯定就要try糟把、catch、finally每次寫太費勁了牲剃,況且一旦修改鎖遣疯,更換其他類型的鎖很麻煩,工作量也很大凿傅。所以缠犀,AOP ,嗯 聪舒,靠譜辨液。 可以在指定方法上加自定義注解,讓AOP 掃描帶有自定義注解的方法就ok了箱残。

細心的同學(xué)會發(fā)現(xiàn)滔迈,紅框內(nèi)容有點不太一樣 @annotation。execution(* com.x.x.x.x.contxroller..*.*(..))" 指的是過濾方法(里面是 [正則表表達式](https://blog.csdn.net/corbin_zhang/article/details/80576809) )被辑。@annotation() 里面放的是注解的全類名燎悍,驚喜不?

/**

*該注解 是在方法上 添加鎖的

*/

@Target({java.lang.annotation.ElementType.PARAMETER, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface MethodLock {

? ? String desc() default "";

}

/**

* 元注解(meta-annotation):

*

*   元注解的作用就是負責(zé)注解其他注解盼理。Java5.0定義了4個標準的meta-annotation類型谈山,它們被用來提供對其它 annotation類型作說明。Java5.0定義的元注解:

*     1.@Target,

*     2.@Retention,

*     3.@Documented,

*     4.@Inherited

*/

/**

* @Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages榜揖、types(類勾哩、接口、枚舉举哟、Annotation類型)思劳、類型成員(方法、構(gòu)造方法妨猩、成員變量潜叛、枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量壶硅、catch參數(shù))威兜。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。

*

*   作用:用于描述注解的使用范圍(即:被描述的注解可以用在什么地方)

*

*   取值(ElementType)有:

*

*     1.CONSTRUCTOR:用于描述構(gòu)造器

*     2.FIELD:用于描述域

*     3.LOCAL_VARIABLE:用于描述局部變量

*     4.METHOD:用于描述方法

*     5.PACKAGE:用于描述包

*     6.PARAMETER:用于描述參數(shù)

*     7.TYPE:用于描述類庐椒、接口(包括注解類型) 或enum聲明

*/

@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })

/**

* @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現(xiàn)在源代碼中椒舵,而被編譯器丟棄;而另一些卻被編譯在class文件中约谈;編譯在class文件中的Annotation可能會被虛擬機忽略笔宿,而另一些在class被裝載時將被讀壤缰印(請注意并不影響class的執(zhí)行,因為Annotation與class在使用上是被分離的)泼橘。使用這個meta-Annotation可以對 Annotation的“生命周期”限制涝动。

*

*   作用:表示需要在什么級別保存該注釋信息,用于描述注解的生命周期(即:被描述的注解在什么范圍內(nèi)有效)

*

*   取值(RetentionPoicy)有:

*

*     1.SOURCE:在源文件中有效(即源文件保留)

*     2.CLASS:在class文件中有效(即class保留)

*     3.RUNTIME:在運行時有效(即運行時保留)

*

*   Retention meta-annotation類型有唯一的value作為成員炬灭,它的取值來自java.lang.annotation.RetentionPolicy的枚舉類型值醋粟。

*/

@Retention(RetentionPolicy.RUNTIME)

/**

* @Documented用于描述其它類型的annotation應(yīng)該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化重归。

* Documented是一個標記注解米愿,沒有成員。

*/

@Documented

/**

* @Inherited 元注解是一個標記注解提前,@Inherited闡述了某個被標注的類型是被繼承的吗货。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個annotation將被用于該class的子類狈网。

*

*   注意:@Inherited annotation類型是被標注過的class的子類所繼承宙搬。類并不從它所實現(xiàn)的接口繼承annotation,方法并不從它所重載的方法繼承annotation拓哺。

*

*   當(dāng)@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME勇垛,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時士鸥,反射代碼檢查將展開工作:檢查class和其父類闲孤,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn),或者到達類繼承結(jié)構(gòu)的頂層烤礁。

*/

@Inherited


代碼如下:


/**

* 鎖注解 切面

*/

@Component //作為一個bean 被spring 掃描到

@Aspect

@Order(100)

1. //order越小越是最先執(zhí)行讼积,但更重要的是最先執(zhí)行的最后結(jié)束。order默認值是2147483647

public class MethodLockAspect {

? ? @Around("@annotation(com.x.x.x.x.annoxtation.MethodLock)")

? ? public Object around(ProceedingJoinPoint joinPoint) {

? ? ? ? return MethodLockAspectUtils.methodLock(joinPoint);

? ? }

}


* @Apsect:將當(dāng)前類標識為一個切面脚仔;

* @Pointcut:定義切點勤众,這里使用的是條件表達式;

* @Before:前置增強鲤脏,就是在目標方法執(zhí)行之前執(zhí)行们颜;

* @AfterReturning:后置增強,方法退出時執(zhí)行猎醇;

* @AfterThrowing:有異常時該方法執(zhí)行窥突;

* @After:最終增強,無論什么情況都會執(zhí)行硫嘶;

* @Afround:環(huán)繞增強阻问;


//切面中 鎖具體的實現(xiàn)

public class MethodLockAspectUtils {

? ? /**

? ? * 互斥鎖 參數(shù)默認false,不公平鎖

? ? */

? ? private static Lock lock = new ReentrantLock(false);

? ? public static Object methodLock(ProceedingJoinPoint joinPoint){

? ? ? ? lock.lock();

? ? ? ? Object obj = null;

? ? ? ? try {

? ? ? ? ? ? obj = joinPoint.proceed();

? ? ? ? } catch (Throwable e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? lock.unlock();

? ? ? ? }

? ? ? ? return obj;

? ? }

}



四沦疾、使用:

在需要添加同步方法上使用注解即可

五称近、注意

這里只是簡單的是鎖機制贡蓖,后期進行更新切換,zookeeper煌茬、redis,mysql等分布式鎖彻桃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坛善,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子邻眷,更是在濱河造成了極大的恐慌眠屎,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肆饶,死亡現(xiàn)場離奇詭異改衩,居然都是意外死亡,警方通過查閱死者的電腦和手機驯镊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門葫督,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人板惑,你說我怎么就攤上這事橄镜。” “怎么了冯乘?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵洽胶,是天一觀的道長。 經(jīng)常有香客問我裆馒,道長姊氓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任喷好,我火速辦了婚禮翔横,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绒窑。我一直安慰自己棕孙,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布些膨。 她就那樣靜靜地躺著蟀俊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪订雾。 梳的紋絲不亂的頭發(fā)上肢预,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音洼哎,去河邊找鬼烫映。 笑死沼本,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锭沟。 我是一名探鬼主播抽兆,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼族淮!你這毒婦竟也來了辫红?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤祝辣,失蹤者是張志新(化名)和其女友劉穎贴妻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝙斜,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡名惩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了孕荠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娩鹉。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖稚伍,靈堂內(nèi)的尸體忽然破棺而出底循,到底是詐尸還是另有隱情,我是刑警寧澤槐瑞,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布熙涤,位于F島的核電站,受9級特大地震影響困檩,放射性物質(zhì)發(fā)生泄漏祠挫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一悼沿、第九天 我趴在偏房一處隱蔽的房頂上張望等舔。 院中可真熱鬧,春花似錦糟趾、人聲如沸慌植。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝶柿。三九已至,卻和暖如春非驮,著一層夾襖步出監(jiān)牢的瞬間交汤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工劫笙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芙扎,地道東北人星岗。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像戒洼,于是被迫代替她去往敵國和親俏橘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355