SpringBoot如何使用@Aspect注解實(shí)現(xiàn)AOP
使用@Aspect 注解實(shí)現(xiàn)AOP
AOP(Aspect Oriented Programming,面向切面編程)是通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
AOP是OOP的延續(xù),是軟件開(kāi)發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。
利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率。
在Spring AOP中業(yè)務(wù)邏輯僅僅只關(guān)注業(yè)務(wù)本身,將日志記錄、性能統(tǒng)計(jì)、安全控制、事務(wù)處理、異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來(lái),從而在改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼。
相關(guān)注解介紹
| 注解 | 作用 |
| @Aspect | 把當(dāng)前類標(biāo)識(shí)為一個(gè)切面 |
| @Pointcut | Pointcut是織入Advice的觸發(fā)條件。每個(gè)Pointcut的定義包括2部分,一是表達(dá)式,二是方法簽名。方法簽名必須是public及void型??梢詫ointcut中的方法看作是一個(gè)被Advice引用的助記符,因?yàn)楸磉_(dá)式不直觀,因此我們可以通過(guò)方法簽名的方式為此表達(dá)式命名。因此Pointcut中的方法只需要方法簽名,而不需要在方法體內(nèi)編寫實(shí)際代碼。 |
| @Around | 環(huán)繞增強(qiáng),目標(biāo)方法執(zhí)行前后分別執(zhí)行一些代碼 |
| @AfterReturning | 返回增強(qiáng),目標(biāo)方法正常執(zhí)行完畢時(shí)執(zhí)行 |
| @Before | 前置增強(qiáng),目標(biāo)方法執(zhí)行之前執(zhí)行 |
| @AfterThrowing | 異常拋出增強(qiáng),目標(biāo)方法發(fā)生異常的時(shí)候執(zhí)行 |
| @After | 后置增強(qiáng),不管是拋出異?;蛘哒M顺龆紩?huì)執(zhí)行 |
一、添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>二、編寫增強(qiáng)類
package com.wuychn.springbootaspect.aspect;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class LogAspect {
/**
* 前置增強(qiáng):目標(biāo)方法執(zhí)行之前執(zhí)行
*
* @param jp
*/
@Before("execution(* com.wuychn.springbootaspect.controller.*.*(..))") // 所有controller包下面的所有方法的所有參數(shù)
public void beforeMethod(JoinPoint jp) {
String methodName = jp.getSignature().getName();
log.info("【前置增強(qiáng)】the method 【" + methodName + "】 begins with " + JSON.toJSONString(jp.getArgs()));
}
/**
* 后置增強(qiáng):目標(biāo)方法執(zhí)行之后執(zhí)行以下方法體的內(nèi)容,不管是否發(fā)生異常。
*
* @param jp
*/
@After("execution(* com.wuychn.springbootaspect.controller.*.*(..)))")
public void afterMethod(JoinPoint jp) {
log.info("【后置增強(qiáng)】this is a afterMethod advice...");
}
/**
* 返回增強(qiáng):目標(biāo)方法正常執(zhí)行完畢時(shí)執(zhí)行
*
* @param jp
* @param result
*/
@AfterReturning(value = "execution(* com.wuychn.springbootaspect.controller.*.*(..)))", returning = "result")
public void afterReturningMethod(JoinPoint jp, Object result) {
String methodName = jp.getSignature().getName();
log.info("【返回增強(qiáng)】the method 【" + methodName + "】 ends with 【" + result + "】");
}
/**
* 異常增強(qiáng):目標(biāo)方法發(fā)生異常的時(shí)候執(zhí)行,第二個(gè)參數(shù)表示補(bǔ)貨異常的類型
*
* @param jp
* @param e
*/
@AfterThrowing(value = "execution(* com.wuychn.springbootaspect.controller.*.*(..))", throwing = "e")
public void afterThorwingMethod(JoinPoint jp, Exception e) {
String methodName = jp.getSignature().getName();
log.error("【異常增強(qiáng)】the method 【" + methodName + "】 occurs exception: ", e);
}
/**
* 環(huán)繞增強(qiáng):目標(biāo)方法執(zhí)行前后分別執(zhí)行一些代碼,發(fā)生異常的時(shí)候執(zhí)行另外一些代碼
*
* @return
*/
/* @Around(value = "execution(* com.wuychn.springbootaspect.controller.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint jp) {
String methodName = jp.getSignature().getName();
Object result = null;
try {
log.info("【環(huán)繞增強(qiáng)中的--->前置增強(qiáng)】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
//執(zhí)行目標(biāo)方法
result = jp.proceed();
log.info("【環(huán)繞增強(qiáng)中的--->返回增強(qiáng)】:the method 【" + methodName + "】 ends with " + result);
} catch (Throwable e) {
result = "error";
log.info("【環(huán)繞增強(qiáng)中的--->異常增強(qiáng)】:the method 【" + methodName + "】 occurs exception " + e);
}
log.info("【環(huán)繞增強(qiáng)中的--->后置增強(qiáng)】:-----------------end.----------------------");
return result;
}*/
}三、Controller
package com.wuychn.springbootaspect.controller;
import com.wuychn.springbootaspect.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class TestController {
@GetMapping("/doNormal")
public String doNormal(String name, String age, User user) {
log.info("【執(zhí)行方法】:doNormal");
return "doNormal";
}
@GetMapping("/doWithException")
public String doWithException(String name, String age, User user) {
log.info("【執(zhí)行方法】:doWithException");
int a = 1 / 0;
return "doWithException";
}
}啟動(dòng)程序,當(dāng)訪問(wèn)doNormal方法時(shí),
日志輸出如下:
2019-05-13 14:36:20.931 INFO 12592 --- [nio-9379-exec-5] c.w.springbootaspect.aspect.LogAspect : 【前置通知】the method 【doNormal】 begins with ["zhangsan","12",{"address":["chengdu","beijing"],"name":"zhangsan"}]
2019-05-13 14:36:20.932 INFO 12592 --- [nio-9379-exec-5] c.w.s.controller.TestController : 【執(zhí)行方法】:doNormal
2019-05-13 14:36:20.932 INFO 12592 --- [nio-9379-exec-5] c.w.springbootaspect.aspect.LogAspect : 【后置通知】this is a afterMethod advice...
2019-05-13 14:36:20.932 INFO 12592 --- [nio-9379-exec-5] c.w.springbootaspect.aspect.LogAspect : 【返回通知】the method 【doNormal】 ends with 【doNormal】
當(dāng)訪問(wèn)doWithException方法時(shí),
日志輸出如下:
2019-05-13 14:45:03.699 INFO 12592 --- [nio-9379-exec-8] c.w.springbootaspect.aspect.LogAspect : 【前置通知】the method 【doWithException】 begins with ["zhangsan","12",{"address":["chengdu","beijing"],"name":"zhangsan"}]
2019-05-13 14:45:03.699 INFO 12592 --- [nio-9379-exec-8] c.w.s.controller.TestController : 【執(zhí)行方法】:doWithException
2019-05-13 14:45:03.699 INFO 12592 --- [nio-9379-exec-8] c.w.springbootaspect.aspect.LogAspect : 【后置通知】this is a afterMethod advice...
2019-05-13 14:45:03.704 ERROR 12592 --- [nio-9379-exec-8] c.w.springbootaspect.aspect.LogAspect : 【異常通知】the method 【doWithException】 occurs exception:
java.lang.ArithmeticException: / by zero
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java實(shí)現(xiàn)protocol傳輸?shù)目蛻舳撕头?wù)端的示例代碼
本文主要介紹了java實(shí)現(xiàn)protocol傳輸?shù)目蛻舳撕头?wù)端的示例代碼,基于TCP協(xié)議的客戶端和服務(wù)端,包括了基本的連接、消息傳遞和關(guān)閉連接的操作,感興趣的可以了解一下2024-07-07
SpringBoot使用Mybatis注解實(shí)現(xiàn)分頁(yè)動(dòng)態(tài)sql開(kāi)發(fā)教程
這篇文章主要為大家介紹了SpringBoot使用Mybatis注解實(shí)現(xiàn)分頁(yè)及動(dòng)態(tài)sql開(kāi)發(fā)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
Jenkin郵件收發(fā)實(shí)現(xiàn)原理及過(guò)程詳解
這篇文章主要介紹了Jenkin郵件收發(fā)實(shí)現(xiàn)原理及過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
nacos注冊(cè)中心調(diào)用服務(wù)失敗的解決方案
nacos注冊(cè)中心出現(xiàn)調(diào)用服務(wù)失敗的情況,可能是因?yàn)樽?cè)了兩個(gè)IP地址,一個(gè)是開(kāi)發(fā)/測(cè)試環(huán)境,一個(gè)是本地啟動(dòng)的IP,解決方法是將本地的IP從注冊(cè)中心下線,以避免干擾其他環(huán)境,確定哪個(gè)IP是開(kāi)發(fā)環(huán)境/測(cè)試環(huán)境的IP,可以使用ifconfig命令查看服務(wù)器的IP地址2026-02-02
MyEclipse整合ssh三大框架環(huán)境搭載用戶注冊(cè)源碼下載
這篇文章主要為大家詳細(xì)介紹了如何使用MyEclipse整合ssh三大框架進(jìn)行環(huán)境搭載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10

