基于springboot實現(xiàn)一個簡單的aop實例
簡介
AOP(Aspect-Oriented Programming:面向切面編程)
aop能將一些繁瑣、重復(fù)、無關(guān)業(yè)務(wù)的邏輯封裝起來,在一個地方進(jìn)行統(tǒng)一處理,常用于日志記錄、事務(wù)管理、權(quán)限控制等,aop能在不改變原有代碼邏輯的基礎(chǔ)上對某個方法、某類方法、或者整個類進(jìn)行無侵入式的加強(qiáng),有效降低了代碼耦合度,并且提高了項目擴(kuò)展性;
ok廢話說完,進(jìn)入正題,如何實現(xiàn)一個aop
要實現(xiàn)aop,首先你要知道你拿aop來干啥,我們今天就以記錄日志來說,因為這個最常用,一般對于重要的數(shù)據(jù)庫操作,我們需要記錄操作人、什么時間、做了什么,關(guān)于做了什么怎么實現(xiàn)我們后面細(xì)講(要想知道做了什么,肯定得知道是哪個方法、并且哪些參數(shù),這些屬于進(jìn)階操作,我們先簡單實現(xiàn)一個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...");
}
}
關(guān)于注解
- @Aspect:告訴spring這是一個切面;
- @Component:將切面交由spring來管理;
- @Pointcut:切入點,直白點就是指定你需要從哪個地方切入,再直白點就是你想增強(qiáng)的目標(biāo)方法,這里需要了解下execution表達(dá)式,可以通過這里來指定你需要切入的方法,可以指定單個方法、整個類的所有方法、類的某些方法、整個包下所有類的所有方法等;
- @Before:目標(biāo)方法執(zhí)行前需要做的事;
- @After:目標(biāo)方法執(zhí)行后需要做的事
還有幾個常用注解:
@Around(能自由的指定在目標(biāo)方法執(zhí)行前后做增強(qiáng)邏輯,需要手動調(diào)用ProceedingJoinPoint的proceed方法來執(zhí)行目標(biāo)方法,不調(diào)用則目標(biāo)方法不會執(zhí)行,如果目標(biāo)方法有返回值,還需手動返回)
@AfterReturning(在目標(biāo)方法正常執(zhí)行完成后做增強(qiáng),如果你需要獲取方法返回值就用它)
@AfterThrowing(當(dāng)目標(biāo)方法執(zhí)行過程中拋出異常時執(zhí)行)
執(zhí)行時機(jī):
切入目標(biāo)方法時,先織入Around,再織入Before,退出目標(biāo)方法時,先織入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對應(yīng)com.example.mydemos.controller包下的,所以該包下的所有類的所有方法都會被增強(qiáng)
先假設(shè)后驗證
按照上述demo
當(dāng)我訪問"/hi"時,會先執(zhí)行@Before對應(yīng)方法,輸出"before…",再執(zhí)行HiController 中的sayHello方法,輸出"hi, good morning~",并且返回"hi bro ~",最后執(zhí)行@After對應(yīng)方法,輸出"after…"
驗證:
項目跑起來訪問"/hi"

控制臺

驗證成功~
一個最基礎(chǔ)的aop實現(xiàn)完畢,接下來搞點進(jìn)階操作
獲取目標(biāo)方法參數(shù)
再來個測試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~";
}
}

現(xiàn)在我們有兩個controller,順便能測試下execution規(guī)則是否生效,我的規(guī)則是com.example.mydemos.controller下的所有方法都增強(qiáng)
HelloController的sayHello方法有兩個參數(shù)title和content,看我們能不能拿到
獲取目標(biāo)方法參數(shù)需要用到JoinPoint,經(jīng)測試,在@Before和@After中均能獲取
@Before("controllerPointcut()")
public void beforeExecute(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
List<Object> list = Arrays.asList(args);
System.out.println("before中的目標(biāo)方法參數(shù)");
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中的目標(biāo)方法參數(shù)");
list.forEach(System.out::println);
System.out.println("after...");
}
joinPoint.getArgs()會返回一個object數(shù)組,這就是你的目標(biāo)方法參數(shù)
測試

結(jié)果

獲取目標(biāo)方法名
所有符合規(guī)則的方法都會被增強(qiáng),那我怎么知道當(dāng)前執(zhí)行的是哪個方法呢?
@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()返回的就是方法名



獲取目標(biāo)方法返回值
這個就需要用到@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,需手動調(diào)用ProceedingJoinPoint.proceed才能執(zhí)行目標(biāo)方法,并且如果目標(biāo)方法有返回值,需要手動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的話需要添加一個參數(shù)returning,用于接收返回值,且AfterReturning注解中的形參要和AfterReturningExecute中的一致,不然識別不到
訪問"/hi"

文中demo已上傳至gitee
順便求個star
么么嘰~
到此這篇關(guān)于基于springboot實現(xiàn)一個簡單的aop的文章就介紹到這了,更多相關(guān)springboot 實現(xiàn)aop內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis Oracle 自增序列的實現(xiàn)方法
這篇文章給大家分享MyBatis Oracle 自增序列的實現(xiàn)方法及mybatis配置oracle的主鍵自增長的方法,非常不錯具有一定的參考借鑒價值,感興趣的朋友一起看看吧2016-11-11
Java后臺防止客戶端重復(fù)請求、提交表單實現(xiàn)原理
這篇文章主要介紹了Java后臺防止客戶端重復(fù)請求、提交表單實現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12
Java/Android 實現(xiàn)簡單的HTTP服務(wù)器
這篇文章主要介紹了Java/Android 如何實現(xiàn)簡單的HTTP服務(wù)器,幫助大家更好的進(jìn)行功能測試,感興趣的朋友可以了解下2020-10-10
Spring-Boot 集成Solr客戶端的詳細(xì)步驟
本篇文章主要介紹了Spring-Boot 集成Solr客戶端的詳細(xì)步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11

