springboot乾貨——(十八)AOP
阿新 • • 發佈:2019-01-07
AOP這個名詞相信大家都不陌生,尤其是在面試的過程中,面試官多多少少都會問到一些關於他的問題,這玩意兒有用嗎?答案是必然的,只是在日常業務邏輯中用的不多,一般像想在某個寫好的程式碼之前插入一些內容,這種情況下用的比較多,那麼接下來我們就一起來看看他在spring boot中的使用。
專案結構如下:
1.新建專案,pom如下:
引入如下jar包即可
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.新建WebLogAspect類
在完成了引入AOP依賴包後,一般來說並不需要去做其他配置。也許在Spring中使用過註解配置方式的人會問是否需要在程式主類中增加@EnableAspectJAutoProxy
來啟用,實際並不需要
package com.gwd.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @FileName WebLogAspect.java * @Description:TODO * @author JackHisen(gu.weidong) * @version V1.0 * @createtime 2018年2月27日 上午9:32:17 * 修改歷史: * 時間 作者 版本 描述 *==================================================== * */ @Component @Aspect public class WebLogAspect { @Pointcut("execution(public * com.gwd.web..*.*(..))") public void weblog() {} @Before("weblog()") public void webBefore() { System.out.println("在更新之前"); System.out.println("stop"); return; } @After("weblog()") public void webAfter() { System.out.println("在更新之後"); } @Around("weblog()") public void webAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("環繞通知前……"); pjp.proceed(); System.out.println("環繞通知後……"); } @AfterReturning("weblog()") public void webAfterReturn() { System.out.println("afterReturning ……"); } }
實現AOP的切面主要有以下幾個要素:
使用@Aspect註解將一個java類定義為切面類
使用@Pointcut定義一個切入點,可以是一個規則表示式,比如下例中某個package下的所有函式,也可以是一個註解等。
根據需要在切入點不同位置的切入內容
使用@Before在切入點開始處切入內容
使用@After在切入點結尾處切入內容
使用@AfterReturning在切入點return內容之後切入內容(可以用來對處理返回值做一些加工處理)
使用@Around在切入點前後切入內容,並自己控制何時執行切入點自身的內容
使用@AfterThrowing用來處理當切入內容部分丟擲異常之後的處理邏輯
3.controller
package com.gwd.web; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @FileName TestController.java * @Description:TODO * @author JackHisen(gu.weidong) * @version V1.0 * @createtime 2018年2月27日 上午10:03:26 * 修改歷史: * 時間 作者 版本 描述 *==================================================== * */ @RestController public class TestController { @RequestMapping("/testAop") public void testAop() { System.out.println("test進行中"); } }
4.測試結果如下
環繞通知前……
在更新之前
stop
test進行中
環繞通知後……
在更新之後
afterReturning ……
在一個方法只被一個aspect類攔截時,aspect類內部的 advice 將按照以下的順序進行執行:
正常情況:
異常情況:
優化:AOP切面的優先順序
由於通過AOP實現,程式得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對Web層做多個切面,校驗使用者,校驗頭資訊等等,這個時候經常會碰到切面的處理順序問題。
所以,我們需要定義每個切面的優先順序,我們需要@Order(i)
註解來標識切面的優先順序。i的值越小,優先順序越高。假設我們還有一個切面是CheckNameAspect
用來校驗name必須為didi,我們為其設定@Order(10)
,而上文中WebLogAspect設定為@Order(5)
,所以WebLogAspect有更高的優先順序,這個時候執行順序是這樣的:
-
在
@Before
中優先執行@Order(5)
的內容,再執行@Order(10)
的內容 -
在
@After
和@AfterReturning
中優先執行@Order(10)
的內容,再執行@Order(5)
的內容
所以我們可以這樣子總結:
- 在切入點前的操作,按order的值由小到大執行
- 在切入點後的操作,按order的值由大到小執行