簡體   English   中英

為 Spring AOP 注釋創建切入點,將注釋放在 class 上,並對 class 中的每個方法執行建議

[英]Create Pointcut for Spring AOP annotation to put annotation on class and execute advice on every method in class

我想在 class 級別上有注釋,它將對注釋 class中的每個方法執行建議。 這還可能嗎。

示例:我想用@DoSomethingForMe注釋OmniDemoService並且我希望method1method2在執行前記錄“看我

這個例子不起作用,我不知道為什么。 當我將 Pointcut 轉換為 Around 並將其與注釋一起使用時(還將注釋 ElementType 更改為方法),一切都在方法級別上工作。 所以我認為這是錯誤定義的切入點。

注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoSomethingForMe {
}

建議:

@Aspect
@Component
public class DoSomethingForMeAdvice {

    private static final Logger logger = LoggerFactory.getLogger(DoSomethingForMeAdvice.class);

    @Pointcut("execution(public * *(..)) && @annotation(DoSomethingForMe)")
    public void anyAnnotatedMethod() {
    }

    @Before("anyAnnotatedMethod()")
    public void acquireExecution() {
        logger.info("look at me");
    }
}

用法:

@Service
@DoSomethingForMe
public class OmniDemoService {

    private static final Logger logger = LoggerFactory.getLogger(OmniDemoService.class);

    public void method1() {
            logger.info("---1---");
    }
    
    public void method2() {
            logger.info("---2---");
    }
}

您的問題是您將切入點定義與建議混淆了。

Pointcut 是瞄准,advice 執行實際的 WhatYouWantToBeExecuted。 比如像

@Pointcut("@annotation(com.omnidemo.advice.DoSomethingForMe)")
public void anyAnnotatedMethod() {
}


@Before("anyAnnotatedMethod()")
public void logMethodCall(JoinPoint jp) {
    String methodName = jp.getSignature().toShortString();
    logger.info("Executing: " + methodName);
}

查看AspectJ 快速參考中關於@annotation()的內容:

主題具有SomeAnnotation類型注釋的任何連接點

您使用@annotation(DoSomethingForMe)但方法執行的“ 主題”是方法 所以這意味着任何注釋@DoSomethingForMe的方法。

使用@this(DoSomethingForMe)@target(DoSomethingForMe)

感謝kriegaex指出必須在運行時評估@this@target ,這會嚴重污染代碼庫(即檢查每個方法)。 所以下一個方法更好:


如果你查看 AspectJ 手冊中關於類型模式的部分,你會發現你可以直接注釋類型。 還請記住使用完全限定的 class 名稱。 所以那將是:

execution(public * (@com.path.DoSomethingForMe *).*(..))

另外,如果你有這么簡單的切入點並且不需要重用它,我認為你可以放棄附加方法,直接在建議中使用它:

@Before("execution(public * (@com.path.DoSomethingForMe *).*(..))")

它說:“在執行帶有@com.path.DoSomethingForMe注釋的類型的任何公共方法之前”,其中“在方法執行之前”的意思是“在方法內部,在開始時”。


或者,如果這個切入點對您來說有點過於復雜,您可以像這樣將注釋匹配和方法匹配分開,正如J Asgarov在他的評論中所建議的那樣:

@Before("execution(public * *(..)) && @within(com.path.DoSomethingForMe)")

該問題的解決方案是使用within for pointcut

@Pointcut("@within(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}

@Before("anyAnnotatedMethod()")
public void acquireExecution() {
    logger.info("look at me");
}

@J Asgarov 在評論中提供的解決方案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM