2019-06-12
面向切面編程(AOP):應(yīng)用程序在運行時,由Spring動態(tài)地將切面織入到應(yīng)用程序指定的業(yè)務(wù)方法中。
切面(Aspect):是把在眾多業(yè)務(wù)中普遍存在的共有代碼抽取出來封裝為切面類集中管理,在程序運行時,由Spring容器運用動態(tài)代理技術(shù)在指定業(yè)務(wù)中自動織入這些切面。
什么是動態(tài)代理
AOP技術(shù)建立在動態(tài)代理機制之上。系統(tǒng)運行時,Spring會動態(tài)創(chuàng)建一個代理對象(Proxy)供使用者調(diào)用,該代理對象已經(jīng)將切面織入到目標對象的業(yè)務(wù)方法中,從而使切面的功能與目標對象的業(yè)務(wù)功能同時得以執(zhí)行。
調(diào)用者直接調(diào)用的其實是Spring動態(tài)生成的代理對象,再由代理對象調(diào)用目標對象完成原始的業(yè)務(wù)處理,而代理對象則已經(jīng)將切面與業(yè)務(wù)邏輯方法進行了合成。
使用注解方式實現(xiàn)AOP
設(shè)計切面類,編寫切面通知
@Component
@Aspect
public class LogAspect {
//注解里使用的變量只能是final String類型
public static final String EDP = "execution(* com.controller.LoginController.*(..))";
@Before(EDP) //前置通知
public void beforeAdvice(JoinPoint joinpoint) {}
@AfterReturning(EDP) //后置通知
public void afterReturningAdvice(JoinPoint joinpoint) {}
@AfterThrowing(pointcut = EDP, throwing = "e") //異常通知
public void afterThrowingAdvice(JoinPoint joinpoint, Exception e) {}
@After(EDP) //最終通知
public void afterAdvice(JoinPoint joinpoint) {}
@Around(EDP) //環(huán)繞通知
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
Object result = pjp.proceed();// 傳遞給連接點對象進行接力處理
return result;
}
}
1.什么是通知
通知(Advice)是切面的具體功能,通常是切面類中的方法。以目標方法連接點為參照,根據(jù)這個通知欲切入到目標方法的位置不同可分為:
- 前置通知(Before):是指在某個連接點方法之前執(zhí)行的通知。如果這個通知不拋出異常,那么該連接點就一定會被執(zhí)行。常用于權(quán)限管理。
- 后置通知(AfterReturning):是指某個連接點方法正常完成(沒有拋出異常)后執(zhí)行的通知。常用于IO流關(guān)閉、臨時文件刪除等。
- 異常通知(AfterThrowing):是指在連接點方法拋出異常退出時執(zhí)行的通知。常用于異常處理、日志記錄等。
- 最終通知(After):是指無論在任何情況下連接點方法退出時執(zhí)行的通知,也就是說無論連接點方法正常退出還是拋出異常退出都會執(zhí)行此通知。類似于異常處理機制中finally塊的作用,常用于釋放資源。
- 環(huán)繞通知(Around):是指包圍連接點方法的通知。這種通知功能非常強大,可以替代前面任意一種通知的功能。常用于日志記錄、事務(wù)處理。
2.AOP注解說明
- @Aspect:使用@Aspect注解的類,Spring會當作切面類處理。
- @Before:前置通知
- @AfterReturning:后置通知
- @AfterThrowing:異常通知
- 必須使用@AfterThrowing(pointcut = 連接點,throwing = "e")的形式,否則會出現(xiàn)”error at ::0 formal unbound in pointcutd”錯誤
- @After:最終通知
- @Around:環(huán)繞通知
- @Pointcut:定義切入點表達式,需要同時定義一個切入點方法,返回值為void且方法體為空
3.切入點表達式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
說明:
- 訪問類型模式(modifiers-pattern):方法的訪問類型,如public表示匹配所有公用方法,此模式通常可省略不寫,除非有特定需求。
- 返回值類型模式(ret-type-pattern):方法的返回值類型,設(shè)置為
*表示匹配任意的返回值類型。 - 類型名稱模式(declaring-type-pattern):表示匹配的包或類的名稱規(guī)則,"
包路徑.*"表示指定包下的所有類均予以匹配,"包路徑..*"則表示指定包及其子包下的所有類均予以匹配,"包路徑.類名"表示指定的類予以匹配。 - 名字模式(name-pattern):匹配方法名,
*表示匹配所有方法,set*表示所有方法名以set開頭的方法。
參數(shù)模式(param-pattern): ()表示匹配不接受任何參數(shù)的方法,(..)表示匹配接受任意數(shù)量參數(shù)的方法,(*)表示匹配接受一個任何類型的參數(shù)的方法, (*,String)則表示匹配接受兩個參數(shù)的方法,第一個參數(shù)可以是任意類型,而第二個參數(shù)必須是String類型。 - 異常模式(throws-pattern):拋出何種類型的異常,如RuntimeException表示匹配拋出RuntimeException異常的方法,此模式通??墒÷圆粚懀怯刑囟ǖ男枨?。
| 切入點正則表達式 | 功 能 描 述 |
|---|---|
| execution(public * *(..)) | 匹配所有公有方法 |
| execution(* set*(..)) | 匹配所有以“set”開頭的方法 |
| execution(* com.action.UserController.*(..)) | 匹配UserController類的所有方法 |
| execution(* com.action..(..)) | 匹配com.action包下所有類的所有方法 |
| execution(* com.action...(..)) | 匹配com.action包及子包下所有類的所有方法 |
修改Spring配置文件
啟動基于注解的AspectJ支持
<aop:aspectj-autoproxy />