知識庫 / Spring RSS 訂閱

Spring 指針表達式簡介

Spring
HongKong
10
02:51 PM · Dec 06 ,2025

1. 概述

在本教程中,我們將討論 Spring AOP 的切面點表達式語言。

首先,我們將介紹面向切面編程中使用的術語。一個 切入點 是程序執行的步驟,例如方法的執行或異常的處理。在 Spring AOP 中,切入點始終代表方法的執行。一個 切面點 是匹配切入點的謂詞,而  切面點表達式語言 是一種描述切面點的程序化方式。

2. 使用方法

一個切片表達式可以作為 @Pointcut 註解的值出現:

@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() {}

方法聲明被稱為 切面簽名。它提供了一個建議註解可以用來引用該切面的名稱:

@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
    ...
}

切面表達式也可以作為 expression 屬性的 aop:pointcut 標籤的值出現:

<aop:config>
    <aop:pointcut id="anyDaoMethod" 
      expression="@target(org.springframework.stereotype.Repository)"/>
</aop:config>

3. 作用點指定者 (Pointcut Designators)

作用點指定者 (Pointcut Designator, PCD) 是 Spring AOP 用於指示匹配目標的關鍵字。 作用點指定者有多種類型,例如匹配方法的執行、類型、方法參數或註解。

3.1. 執行 (Execution)

Spring PCD(程序切面定義)的核心是 執行 (execution),它與方法執行的 JoinPoint 匹配:

@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

此示例切片將精確匹配 findById 方法的執行,該方法位於 FooDao 類中。 這種方法有效,但不夠靈活。 假設我們想要匹配 FooDao 類中的所有方法,這些方法可能具有不同的簽名、返回值和參數。 要實現這一點,可以使用通配符:

@Pointcut("execution(* com.baeldung.pointcutadvice.dao.FooDao.*(..))")

在這裏,第一個通配符匹配任何返回值,第二個匹配任何方法名,而 (..) 模式匹配零個或多個參數。

3.2. within

通過使用 within PCD,可以限制匹配到特定類型的連接點,從而達到與上一部分相同的結果。

@Pointcut("within(com.baeldung.pointcutadvice.dao.FooDao)")

我們還可以匹配 com.baeldung 包或其任何子包中的任何類型:

@Pointcut("within(com.baeldung..*)")

3.3. <em this</em> 和 <em target</em>

<em this</em> 限制匹配操作發生在 Bean 引用是指定類型的連接點,而<em target 則限制匹配操作發生在目標對象是指定類型的連接點。前者適用於 Spring AOP 創建基於 CGLIB 的代理,後者則用於 JDK 代理創建的情況。假設目標類實現了接口:`

public class FooDao implements BarDao {
    ...
}

在這種情況下,Spring AOP 將使用基於 JDK 的代理,並且應該使用 target PCD,因為代理對象將是 Proxy 類的實例,並實現 BarDao 接口:

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

另一方面,如果 <em >FooDao</em > 沒有實現任何接口,或者 <em >proxyTargetClass</em > 屬性設置為 true,則代理對象將是 <em >FooDao</em > 的子類,我們可以使用 this PCD:

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

3.4. args

我們可以使用此 PCD 來匹配特定方法參數:

@Pointcut("execution(* *..find*(Long))")

此切片匹配任何以“find”開頭的方法,並且只有一個 Long 類型的參數。如果想要匹配具有任意數量參數的方法,但第一個參數仍然是 Long 類型,則可以使用以下表達式:

@Pointcut("execution(* *..find*(Long,..))")

3.5. <em @target PCD (與上述 <em @target PCD 區分) 限制了匹配於執行對象類具有指定類型的標註的連接點:

@Pointcut("@target(org.springframework.stereotype.Repository)")

3.6. <em @args

這段 PCD 限制了匹配到具有指定類型的註解的實際參數的 join 點。 假設我們想要跟蹤所有接受帶有 <em @Entity 註解的 beans 的方法:

@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)")
public void methodsAcceptingEntities() {}

為了訪問斷言,我們應該向建議提供一個 JoinPoint 參數:

@Before("methodsAcceptingEntities()")
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
    logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}

3.7. <em @within</em>

此 PCD 僅限於在具有指定標註的類型內的連接點進行匹配:

@Pointcut("@within(org.springframework.stereotype.Repository)")

哪一個等價於:

@Pointcut("within(@org.springframework.stereotype.Repository *)")

3.8. <em @annotation</em>

這段 PCD 限制匹配僅限於具有指定標註的連接點,即連接點的主體具有該標註。例如,我們可以創建 <em @Loggable</em> 標註:

@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)")
public void loggableMethods() {}

然後我們可以記錄標記了該註解的方法執行過程:

@Before("loggableMethods()")
public void logMethod(JoinPoint jp) {
    String methodName = jp.getSignature().getName();
    logger.info("Executing method: " + methodName);
}

4. 組合點表達式

點表達式可以使用 &&||! 運算符進行組合:

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}

@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}

@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

5. 結論

在本文中,我們通過一些示例介紹了 Spring AOP 中的切面表達式。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.