三分鐘看懂,Java開發如何使用SpringBoot中的AOP處理

三分鐘看懂,Java開發如何使用SpringBoot中的AOP處理

可獲得兩大新人禮包

36份一線互聯網Java面試電子書

84個Java稀缺面試題視頻

1. 什麼是AOP

AOP:Aspect Oriented Programming的縮寫,意為:面向切面編程。面向切面編程的目標就是分離關注點。什麼是關注點呢?就是你要做的事,就是關注點。假如你是個公子哥,沒啥人生目標,天天就是衣來伸手,飯來張口,整天只知道玩一件事!那麼,每天你一睜眼,就光想著吃完飯就去玩(你必須要做的事),但是在玩之前,你還需要穿衣服、穿鞋子、疊好被子、做飯等等等等事情,這些事情就是你的關注點,但是你只想吃飯然後玩,那麼怎麼辦呢?這些事情通通交給別人去幹。在你走到飯桌之前,有一個專門的僕人A幫你穿衣服,僕人B幫你穿鞋子,僕人C幫你疊好被子,僕人C幫你做飯,然後你就開始吃飯、去玩(這就是你一天的正事),你幹完你的正事之後,回來,然後一系列僕人又開始幫你幹這個幹那個,然後一天就結束了!

AOP的好處就是你只需要幹你的正事,其它事情別人幫你幹。也許有一天,你想裸奔,不想穿衣服,那麼你把僕人A解僱就是了!也許有一天,出門之前你還想帶點錢,那麼你再僱一個僕人D專門幫你幹取錢的活!這就是AOP。每個人各司其職,靈活組合,達到一種可配置的、可插拔的程序結構。

2. SpringBoot中的AOP處理

2.1 AOP依賴

使用AOP,首先需要引入AOP的依賴。

org.springframework.boot

spring-boot-starter-aop

2.2 實現AOP切面

SpringBoot中使用AOP非常簡單,假如我們要在項目中打印一些log,在引入了上面的依賴之後,我們新建一個類LogAspectHandler,用來定義切面和處理方法。只要在類上加個@Aspect註解即可。

@Aspect

@Component

public class LogAspectHandler {

}

這裡主要介紹幾個常用的註解:

1.@Pointcut:定義一個切面,即上面所描述的關注的某件事入口。

2.@Before:在做某件事之前做的事。

3.@After:在做某件事之後做的事。

4.@AfterReturning:在做某件事之後,對其返回值做增強處理。

5.@AfterThrowing:在做某件事拋出異常時,處理。

具體看如下代碼註釋:

/**

* 使用AOP處理log

* @author shengwu ni

* @date 2018/05/04 20:24

*/

@Aspect

@Component

public class LogAspectHandler {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

/**

* 定義一個切面,攔截cn.nxcoder.blog.controller包下的所有方法

*/

@Pointcut("execution(* com.itcodai.demo7.controller.*.*(..))")

public void pointCut() {}

/**

* 在上面定義的切面方法之前執行該方法

* @param joinPoint jointPoint

*/

@Before("pointCut()")

public void doBefore(JoinPoint joinPoint) {

// 獲取執行的方法和參數

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("即將執行方法: {}", classMethod);

}

/**

* 在上面定義的切面方法之後執行該方法

* @param joinPoint jointPoint

*/

@After("pointCut()")

public void doAfter(JoinPoint joinPoint) {

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("方法{}已經執行完", classMethod);

}

/**

* 在上面定義的切面方法返回後執行該方法,可以捕獲返回對象或者對返回對象進行增強

* @param joinPoint jointPoint

* @param Object result

*/

@AfterReturning(pointcut = "pointCut()", returning = "result")

public void doAfterReturning(JoinPoint joinPoint, Object result) {

Signature signature = joinPoint.getSignature();

String classMethod = signature.getDeclaringTypeName() + "." + signature.getName();

logger.info("方法{}執行完畢,返回參數為:{}", classMethod, result);

logger.info("對返回參數進行業務上的增強:{}", result + "增強版");

}

/**

* 在上面定義的切面方法執行拋異常時,執行該方法

* @param joinPoint jointPoint

* @param ex ex

*/

@AfterThrowing(pointcut = "pointCut()", throwing = "ex")

public void afterThrowing(JoinPoint joinPoint, Throwable ex) {

Signature signature = joinPoint.getSignature();

String method = signature.getDeclaringTypeName() + "." + signature.getName();

// 處理異常的邏輯

logger.info("執行方法{}出錯,異常為:{}", method, ex);

}

}

JointPoint對象很有用,它可以獲取請求的方法名,包括參數(joinPoint.getArgs())等,在@Before中,我們還可以獲取用戶訪問的ip等信息,比如:

// 獲取請求的url和ip

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletRequest request = attributes.getRequest();

String url = request.getRequestURL().toString();

String ip = request.getRemoteAddr();

在@AfterReturning中,屬性returning的值必須要和參數保持一致,否則檢測不到。對於返回值的增強,可以根據業務需要做相應的封裝,上面只是做個demo。 下面寫個Controller來測試一下:

@RestController

public class TestController {

@GetMapping("/test/{name}")

public String testAop(@PathVariable String name) {

return "Hello " + name;

}

}

啟動程序,在瀏覽器中輸入:localhost:8080/test/aop看下結果:

即將執行方法: com.itcodai.demo7.controller.TestController.testAop

方法com.itcodai.demo7.controller.TestController.testAop已經執行完

方法com.itcodai.demo7.controller.TestController.testAop執行完畢,返回參數為:Hello aop

對返回參數進行業務上的增強:Hello aop增強版

當然了,除了如上定義切面的方式外,還可以針對某個註解定義切面,比如我們對具有@GetMapping註解的方法做切面,可以如下定義切面:

@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

public void annotationCut() {}

然後在其他方法上使用該切面,就會切入註解是@GetMapping的方法。因為在實際項目中,可能對於不同的註解有不同的邏輯處理,比如@GetMapping、@PostMapping、@DeleteMapping等。所以這種按照註解的切入方式也很常用。


分享到:


相關文章: