spring 核心與原始碼解析(3):AOP如何使用
AOP,面向切面程式設計,是Spring的另一核心。
在剖析AOP的實現原理前,需要先對如何使用AOP做一番探索,本節仍然使用spring boot作為實驗框架。
首先說明AOP的使用場景:日誌記錄,事務記錄等。
即可以看出,AOP的使用方式,採取類似注入式的模式,在某個方法執行前或者執行後,首先執行AOP中規定的程式碼。
這裡涉及到兩個性質不同的方法區分,普通方法和AOP中的方法。AOP中的方法會在普通方法執行時執行,那麼這個AOP方法為什麼不融合到普通方法中呢?因為AOP方法可以被複用。
那麼事不宜遲,首先看一個例子:
//controller
@RestController
public class HealthCheckController {
@RequestMapping(value ="/health" ,method = RequestMethod.GET)
public String health_check(){
System.out.println("health");
return "ok";
}
}
//aspect
@Aspect
@Component
public class ControllerAspect {
@Pointcut("execution(* com.example.source.controller..*(..)) " )
public void controllerMethodPointcut(){}
@Before("controllerMethodPointcut()")
public void Interceptor(){
System.out.println("method start");
}
}
在spring boot啟動後,呼叫/health
介面後就會輸出
method start
health
這是因為,我們在ControllerAspect 中定義了切入點——HealthCheckController,針對HealthCheckController中的任意方法呼叫,一開始都會先呼叫ControllerAspect 中的Interceptor()方法,在執行HealthCheckController中的具體方法。
那麼如何理解上述註解中各引數的含義?
切入點(Pointcut)的註解
光憑猜,大概也能猜出上述程式碼片段中@Pointcut的含義:定位哪些方法需要執行AOP方法。
那麼@Pointcut的作用就是定義需要執行AOP方法的方法了,這些方法我們稱為切入點。
那麼@Pointcut的註解的具體引數也就是讓我們配置如何找到那些需要執行AOP方法的方法。
大體上來說,@Pointcut裡可以使用以下幾個引數:
execution()
@annotation()
this()
args()
@args()
target()
@target()
within()
@within()
execution()
最常用,直接定義那些方法需要AOP方法。
其完整的格式是:
execution([modifiers-pattern] ret-type-pattern [declaring-type-pattern] name-pattern(param-pattern)[throws-pattern])
其中,
modifiers-pattern
:修飾符匹配,如public,private
ret-type-pattern
:返回值匹配,如String
declaring-type-pattern
:類路徑匹配,如 com.example.source
name-pattern
:方法名匹配,如Test*(表示以Test開始的方法)
param-pattern
:引數匹配,如String
throws-pattern
:異常型別匹配
一個完整的execution()寫法如下:
@Pointcut("execution(" +
"public " +
"String " +
"com.example.source.controller.HealthCheckController " + ".health_check" +
"(..))")
分別對應了上面的引數。
上述程式碼時一開始的樣例@Pointcut("execution(* com.example.source.controller..*(..)) ")
的變體,效果不變。
關於execution()可參考:execution()註解參考
@annotation()
通過對execution()的語法解析我們發現,execution()是直接匹配實體方法名的,如果想匹配註解,則無能為力。幸好@annotation()就是幹這個的。
@annotation()括號中需要填入註解類,比如:
@annotation(org.springframework.web.bind.annotation.RequestMapping))
那麼就是關聯到被RequestMapping註解的方法。
需要注意的是@annotation()定位到方法一級。
@within和@target針對類的註解,@annotation是針對方法的註解
切面的時機
主要是指在切入點之前,之後,還是其他順序執行。
上面的程式碼中,用@Before表示在切入點之前,先執行AOP方法,然後在執行普通方法,如果使用@After,那麼就表示先執行普通方法,在執行AOP方法。
該類註解共有五種:@Before,@After,@AfterReturning,@AfterThrowing,@Around。
參考spring AOP pointcut 詳細用法和