[英]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.