簡體   English   中英

將 AOP 添加到 Spring 引導過程將方法返回的 object 更改為 null

[英]Adding AOP to Spring Boot process changes object returned by method to null

我想將用於日志記錄的 AOP 添加到我的 Spring 引導應用程序中。 但它似乎以意想不到的方式改變了我的應用程序的行為。

例如,我的應用程序有一個方法doThis() ,它創建了一個MyObject實例:

MyObject myObect = doThis();  // a non-null myObject is returned from doThis()

這很好用,並且myObject按預期填充了從doThis()返回的實例。 但我希望doThis()方法可以通過 AOP 記錄一些消息。

那么我添加以下方面 class:

@Aspect
public class LoggingAspect {

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

    @Around("execution(* my.service.package.*.*(..))")
    public void log(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("before");
        joinPoint.proceed();
        logger.info("after");
    }
}

而且我還添加了這個配置class:

@Configuration
@ComponentScan(basePackages = "my.service.package")
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public LoggingAspect aspect() {
        return new LoggingAspect();
    }
}

然而,現在當我運行我的應用程序時,日志語句確實出現了,正如預期的那樣——但現在同樣的doThis()方法顯然返回了 null object:

MyObject myObect = doThis(); // myObject is now unexplainedly null

但這不是真的! 我的意思是當我在doThis()的最后一行設置斷點時,它即將返回的 MyObject 實例顯然不是 null 它已在doThis()方法中創建和填充。 那么它在哪里 go 呢? doThis()清楚地返回一個非空的 MyObject 實例時,為什么myObject沒有被填充?

似乎這個方面以某種方式使從doThis()返回的 object 無效。 有沒有人見過這個? 有什么辦法嗎?

我相信我的執行語句中的第一個*應該表明被攔截的方法可以有任何返回類型。 但是,我截獲的方法的返回值似乎以某種方式更改為 null。

我正在研究如何根據評論創建一個“最小的可重現示例”,我將在此處添加該評論,但這似乎是一個相當標准的 AOP 用例,因此在此期間將其扔掉以防有人可能有一些見識。

您犯了一個簡單的初學者 AOP 錯誤:您的@Around建議繼續執行,但不返回procedure proceed()調用的結果。 你的通知方法有一個 void 返回類型,你攔截的目標方法沒有。 因此,建議隱式返回null 順便說一句,對於像int這樣的原始類型,由於返回類型不兼容,這甚至不起作用並引發異常。 實際上,我很驚訝 Spring AOP,奇怪的是,如果環繞建議返回 void,它甚至會攔截非 void 方法,因為在這種情況下,AFAIR 原生 AspectJ 不會匹配非 void 方法。

所以,你可以做什么?

  • 如果您真的認為需要,請保留@Around建議。 通常,僅當您想做的不僅僅是記錄事情時,例如修改方法參數或返回值、處理異常或其他可能改變控制流的事情時,才會出現這種情況:

     @Around("execution(* my.service.package.*.*(..))") public Object log(ProceedingJoinPoint joinPoint) throws Throwable { logger.info("[BEFORE] " + joinPoint); try { return joinPoint.proceed(); } finally { logger.info("[AFTER] " + joinPoint); } }
  • 或者保持簡單,只使用一對@Before@After通知方法,如果不需要將數據從一個通知傳輸到另一個通知。 這要簡單得多,因為您不需要繼續,使用try-finally或返回任何內容:

     @Before("execution(* my.service.package.*.*(..))") public void logBefore(JoinPoint joinPoint) { logger.info("[BEFORE] " + joinPoint); } @After("execution(* my.service.package.*.*(..))") public void logAfter(JoinPoint joinPoint) { logger.info("[AFTER] " + joinPoint); }

    在這里,您還可以將重復的切入點表達式分解到它自己的@Pointcut中,並從兩個通知方法中簡單地引用它。

暫無
暫無

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

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