1. 程式人生 > >spring 核心與原始碼解析(3):AOP如何使用

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 詳細用法