磐石網(wǎng)站seo站外推廣方式
前言:本文不介紹 AOP 的基本概念、動態(tài)代理方式實現(xiàn) AOP,以及 Spring 框架去實現(xiàn) AOP。本文重點介紹 Spring Boot 項目中如何使用 AOP,也就是實際項目開發(fā)中如何使用 AOP 去實現(xiàn)相關(guān)功能。
如果有需要了解 AOP 的概念、動態(tài)代理實現(xiàn) AOP 的,請查看我的另外一篇文章:
一篇文章帶你深入了解 AOP
正文開始:
Spring Boot中實際應(yīng)用AOP
1、之前介紹的實現(xiàn) AOP 的方式中是有 XML 文件設(shè)置。但在 Spring Boot 中,沒有 XML 文件,那怎么設(shè)置 AOP?
2、實際應(yīng)用中:MVC三層架構(gòu),現(xiàn)需要在控制器中統(tǒng)一進行日志的輸出(有各種各樣的控制器),那怎么實現(xiàn)?(也就是說實際應(yīng)用中如何實現(xiàn)?)
1、Cal 接口、CalIml 接口實現(xiàn)類 還是跟 Spring框架實現(xiàn)AOP 中一樣。之前的兩個依賴不要,添加這個依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、控制器中需要打印日志,比如:調(diào)控制器中的哪個方法(接口)、方法有哪些參數(shù)、返回值。當然,你肯定可以在每個方法中寫,但顯然這不現(xiàn)實。這里用 AOP 方法將打印日志抽離出來,然后需要的時候嵌入到每個方法中
//以下代碼僅是為了測試,代碼不規(guī)范,請注意。@RestController
@RequestMapping("/aop")
public class AopSpringBootTestHandler {@GetMapping("/findAll")public List<Account> findAll() {return Arrays.asList(new Account(1, "張三", 25), new Account(2, "李四", 26));}@GetMapping("/findById/{id}")public Account findById(@PathVariable Integer id) {return new Account(1, "張三", 25);}@GetMapping("/add")public boolean add() {return true;}@GetMapping("/update")public boolean update() {return true;}@GetMapping("/delete/{id}")public boolean delete(@PathVariable Integer id) {return true;}
}
自定義注解
3、自定義注解(比如:創(chuàng)建一個 annotation 的包,然后創(chuàng)建一個 LogAnnotation(可自定義,比如這里是打印日志的注解))
為什么要這個自定義注解?----> 首先你要讓 AOP 知道你調(diào)了哪些方、哪些方法需要讓 AOP 進行處理,所以就要讓 AOP 知道這些方法,怎么知道? ----> 通過自定義注解
其次并不是所有的方法都需要進行 AOP 處理,所以通過 注解 標記。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {//使用注解時,給注解中添加值String value() default "";
}
說明:@Target、@Retention、@Documented 都是元注解(描述注解的注解)
@Target
表示該注解的使用目標,其中 @Target(ElementType.METHOD)
表示只能使用在方法上:
@Retention(RetentionPolicy.RUNTIME)
表示在運行時使用該注解。
@interface
標志這是一個注解。
String value() default "";
固定寫法,表示在使用注解的時候,可以添加值,默認為空:
**使用自定義注解:**需要進行 AOP 處理的方法,標記即可
4、標記完后,同理,需要切面類,執(zhí)行非業(yè)務(wù)代碼(比如這里是輸出日志):
@Component
@Aspect
public class CreateAspectUtil {/*我們利用自定義注解標記了哪些方法需要進行AOP處理,那真正需要處理的時候,怎么找到這些標記?通過 Pointcut(切入點)找到這些標記所以這個方法就是為了找到標記,必須是空方法體*/@Pointcut("@annotation(com.example.test.aopspringboottest.annotation.LogAnnotation)")public void logPointCut() {}/*找到標記后,怎么執(zhí)行日志?1、跟之前一樣,有@Before前置通知、@After后置通知等等@Around注解就是將各種通知統(tǒng)一到一起,然后將找標記的方法放進去2、連接點 ProceedingJoinPoint 是 joinPoint 的子接口,只是ProceedingJoinPoint中有這個proceed()方法,為了獲取方法的返回值*/@Around("logPointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {String methodName = joinPoint.getSignature().getName();String methodArgs = Arrays.toString(joinPoint.getArgs());System.out.println(methodName + "方法的參數(shù)是:" + methodArgs);return joinPoint.proceed(); //返回目標方法(也就是業(yè)務(wù)代碼)中的返回值}
}
演示: 啟動啟動類后,直接訪問:
沒加標記的就不會打印日志。
注意:現(xiàn)在還要求輸出自定義注解中的值, 怎么辦?----> 通過反射獲取注解即可
既然獲取注解,注解是添加在方法上的,所以先通過反射獲取方法,怎么獲取?----> 只有一個連接點,所以還是通過連接點:
@Around("logPointcut()")
public Object around(ProceedingJointPoint jointPoint) throws Throwable {//通過連接點獲取到方法的簽名MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();//通過方法簽名獲取到方法Method method = methodSignature.getMethod();//拿到方法后,拿注解:把自定義注解的運行時類給它LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);if (annotation != null) {//拿注解中的值,通過里面的value方法String value = annotation.value();//這個value就是注解里面的內(nèi)容System.out.println(value);}
}