基於springboot實現一個簡單的aop實例
簡介
AOP(Aspect-Oriented Programming:面向切面編程)
aop能將一些繁瑣、重復、無關業務的邏輯封裝起來,在一個地方進行統一處理,常用於日志記錄、事務管理、權限控制等,aop能在不改變原有代碼邏輯的基礎上對某個方法、某類方法、或者整個類進行無侵入式的加強,有效降低瞭代碼耦合度,並且提高瞭項目擴展性;
ok廢話說完,進入正題,如何實現一個aop
要實現aop,首先你要知道你拿aop來幹啥,我們今天就以記錄日志來說,因為這個最常用,一般對於重要的數據庫操作,我們需要記錄操作人、什麼時間、做瞭什麼,關於做瞭什麼怎麼實現我們後面細講(要想知道做瞭什麼,肯定得知道是哪個方法、並且哪些參數,這些屬於進階操作,我們先簡單實現一個aop)
我們先new一個切面
@Aspect @Component public class LogAspect { @Pointcut("execution(* com.example.mydemos.controller..*(..))") public void controllerMenthod() { } @Before("controllerPointcut()") public void beforeExecute() { System.out.println("before..."); } @After("controllerPointcut()") public void afterExecute() { System.out.println("after..."); } }
關於註解
- @Aspect:告訴spring這是一個切面;
- @Component:將切面交由spring來管理;
- @Pointcut:切入點,直白點就是指定你需要從哪個地方切入,再直白點就是你想增強的目標方法,這裡需要瞭解下execution表達式,可以通過這裡來指定你需要切入的方法,可以指定單個方法、整個類的所有方法、類的某些方法、整個包下所有類的所有方法等;
- @Before:目標方法執行前需要做的事;
- @After:目標方法執行後需要做的事
還有幾個常用註解:
@Around(能自由的指定在目標方法執行前後做增強邏輯,需要手動調用ProceedingJoinPoint的proceed方法來執行目標方法,不調用則目標方法不會執行,如果目標方法有返回值,還需手動返回)
@AfterReturning(在目標方法正常執行完成後做增強,如果你需要獲取方法返回值就用它)
@AfterThrowing(當目標方法執行過程中拋出異常時執行)
執行時機:
切入目標方法時,先織入Around,再織入Before,退出目標方法時,先織入Around,再織入AfterReturning,最後才織入After
來個測試controller
就是個平平無奇的普通controller
@RestController public class HiController { @GetMapping("/hi") public String sayHello() { System.out.println("hi, good morning~"); return "hi bro ~"; } }
我這個controller是放在Pointcut對應com.example.mydemos.controller包下的,所以該包下的所有類的所有方法都會被增強
先假設後驗證
按照上述demo
當我訪問”/hi”時,會先執行@Before對應方法,輸出”before…”,再執行HiController 中的sayHello方法,輸出”hi, good morning~”,並且返回”hi bro ~”,最後執行@After對應方法,輸出”after…”
驗證:
項目跑起來訪問”/hi”
控制臺
驗證成功~
一個最基礎的aop實現完畢,接下來搞點進階操作
獲取目標方法參數
再來個測試controller
@RestController public class HelloController { @GetMapping("/hello/{title}/{content}") public String sayHello(@PathVariable("title") String title, @PathVariable("content") String content) { System.out.println(title + ":" + content); return "hello ya~"; } }
現在我們有兩個controller,順便能測試下execution規則是否生效,我的規則是com.example.mydemos.controller下的所有方法都增強
HelloController的sayHello方法有兩個參數title和content,看我們能不能拿到
獲取目標方法參數需要用到JoinPoint,經測試,在@Before和@After中均能獲取
@Before("controllerPointcut()") public void beforeExecute(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); List<Object> list = Arrays.asList(args); System.out.println("before中的目標方法參數"); list.forEach(System.out::println); System.out.println("before..."); } @After("controllerPointcut()") public void afterExecute(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); List<Object> list = Arrays.asList(args); System.out.println("after中的目標方法參數"); list.forEach(System.out::println); System.out.println("after..."); }
joinPoint.getArgs()會返回一個object數組,這就是你的目標方法參數
測試
結果
獲取目標方法名
所有符合規則的方法都會被增強,那我怎麼知道當前執行的是哪個方法呢?
@Before("controllerPointcut()") public void beforeExecute(JoinPoint joinPoint) { String name = joinPoint.getSignature().getName(); System.out.println("before中的方法名:"+name); System.out.println("before..."); } @After("controllerPointcut()") public void afterExecute(JoinPoint joinPoint) { String name = joinPoint.getSignature().getName(); System.out.println("after中的方法名:"+name); System.out.println("after..."); }
joinPoint.getSignature().getName()返回的就是方法名
獲取目標方法返回值
這個就需要用到@Around或者@AfterReturning
一、@Around
@Around("controllerPointcut()") public Object aruondExecute(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around before..."); String name = joinPoint.getSignature().getName(); Object o = joinPoint.proceed(); System.out.println("方法" + name + "的返回值是" + o); System.out.println("around after..."); return o; }
註意,如果用around,需手動調用ProceedingJoinPoint.proceed才能執行目標方法,並且如果目標方法有返回值,需要手動return
訪問”/hi”
二、@AfterReturning
@AfterReturning(value = "controllerPointcut()", returning = "result") public void AfterReturningExecute(JoinPoint joinPoint, Object result) { System.out.println("AfterReturning..."); String name = joinPoint.getSignature().getName(); System.out.println("方法" + name + "的返回值是" + result); }
用AfterReturning的話需要添加一個參數returning,用於接收返回值,且AfterReturning註解中的形參要和AfterReturningExecute中的一致,不然識別不到
訪問”/hi”
文中demo已上傳至gitee
順便求個star
麼麼嘰~
到此這篇關於基於springboot實現一個簡單的aop的文章就介紹到這瞭,更多相關springboot 實現aop內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 基於SpringAop中JoinPoint對象的使用說明
- 淺談@Aspect@Order各個通知的執行順序
- Springboot如何使用Aspectj實現AOP面向切面編程
- SpringBoot整合Web之AOP配置詳解
- SpringBoot開發教程之AOP日志處理