1. 程式人生 > >springboot乾貨——(十八)AOP

springboot乾貨——(十八)AOP

AOP這個名詞相信大家都不陌生,尤其是在面試的過程中,面試官多多少少都會問到一些關於他的問題,這玩意兒有用嗎?答案是必然的,只是在日常業務邏輯中用的不多,一般像想在某個寫好的程式碼之前插入一些內容,這種情況下用的比較多,那麼接下來我們就一起來看看他在spring boot中的使用。

專案結構如下:


1.新建專案,pom如下

引入如下jar包即可

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

2.新建WebLogAspect類

在完成了引入AOP依賴包後,一般來說並不需要去做其他配置。也許在Spring中使用過註解配置方式的人會問是否需要在程式主類中增加@EnableAspectJAutoProxy來啟用,實際並不需要

package com.gwd.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/** 
* @FileName WebLogAspect.java
* @Description:TODO
* @author JackHisen(gu.weidong)
* @version V1.0
* @createtime 2018年2月27日 上午9:32:17 
* 修改歷史:
* 時間           作者          版本        描述
*====================================================  
*
*/
@Component
@Aspect
public class WebLogAspect {
	@Pointcut("execution(public * com.gwd.web..*.*(..))")
	public void weblog() {}
	
	@Before("weblog()")
	public void webBefore() {
		System.out.println("在更新之前");
		System.out.println("stop");
		return;
	}
	
	@After("weblog()")
	public void webAfter() {
		System.out.println("在更新之後");
	}
	
	@Around("weblog()")
	public void webAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("環繞通知前……");
		pjp.proceed();
		System.out.println("環繞通知後……");
	}
	
	@AfterReturning("weblog()")
	public void webAfterReturn() {
		System.out.println("afterReturning ……");
	}
}
實現AOP的切面主要有以下幾個要素:

使用@Aspect註解將一個java類定義為切面類
使用@Pointcut定義一個切入點,可以是一個規則表示式,比如下例中某個package下的所有函式,也可以是一個註解等。
根據需要在切入點不同位置的切入內容
使用@Before在切入點開始處切入內容
使用@After在切入點結尾處切入內容
使用@AfterReturning在切入點return內容之後切入內容(可以用來對處理返回值做一些加工處理)
使用@Around在切入點前後切入內容,並自己控制何時執行切入點自身的內容
使用@AfterThrowing用來處理當切入內容部分丟擲異常之後的處理邏輯


3.controller
package com.gwd.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/** 
* @FileName TestController.java
* @Description:TODO
* @author JackHisen(gu.weidong)
* @version V1.0
* @createtime 2018年2月27日 上午10:03:26 
* 修改歷史:
* 時間           作者          版本        描述
*====================================================  
*
*/
@RestController
public class TestController {
	@RequestMapping("/testAop")
	public void testAop() {
		System.out.println("test進行中");
	}
}

4.測試結果如下
環繞通知前……
在更新之前
stop
test進行中
環繞通知後……
在更新之後
afterReturning ……

在一個方法只被一個aspect類攔截時,aspect類內部的 advice 將按照以下的順序進行執行:

正常情況: 


異常情況:


優化:AOP切面的優先順序

由於通過AOP實現,程式得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對Web層做多個切面,校驗使用者,校驗頭資訊等等,這個時候經常會碰到切面的處理順序問題。

所以,我們需要定義每個切面的優先順序,我們需要@Order(i)註解來標識切面的優先順序。i的值越小,優先順序越高。假設我們還有一個切面是CheckNameAspect用來校驗name必須為didi,我們為其設定@Order(10),而上文中WebLogAspect設定為@Order(5),所以WebLogAspect有更高的優先順序,這個時候執行順序是這樣的:

  • @Before中優先執行@Order(5)的內容,再執行@Order(10)的內容
  • @After@AfterReturning中優先執行@Order(10)的內容,再執行@Order(5)的內容

所以我們可以這樣子總結:

  • 在切入點前的操作,按order的值由小到大執行
  • 在切入點後的操作,按order的值由大到小執行
部分內容來源於:http://blog.didispace.com/springbootaoplog/