gpt4 book ai didi

java - Spring AOP - 切入点仅在从 lambda 调用 joinPoint.proceed 时应用于方法

转载 作者:行者123 更新时间:2023-12-04 03:48:58 26 4
gpt4 key购买 nike

(标题不是最好的,但我找不到一个好的方式来表达以下问题)

给定

@Aspect
@Component
class MyAspect {
@Autowired private MyService service;

@Around("@target(org.springframework.ws.server.endpoint.annotation.Endpoint)")
public Object aroundEndpoint(ProceedingJoinPoint joinPoint) {
return service.around(joinPoint::proceed);
}

@Around("@target(org.springframework.stereotype.Service)") // And some other expressions to exclude `MyService`
public Object aroundService(ProceedingJoinPoint joinPoint) throws Throwable {
// ...
}
}

@Service
class MyService {
// My own Callable<T> with Throwable instead of Exception
public Object around(Callable<?> callable) throws Throwable {
// Do stuff
Object returnValue = callable.call();
// Do stuff
return returnValue;
}
}

当一个端点方法被调用时,它被aroundEndpoint拦截。如果我立即调用 joinPoint.proceed(),一切都会按预期进行。但是,如果我将它作为方法引用(或 lambda)传递给 MyService.around,然后 then 调用它,它会与我的服务切入点和我的 around 服务相匹配建议应用于它。

我做了一些调试,这是我看到的:在 AspectJExpressionPointcut.matches 中,thisObjecttargetObject 指的是我在前者中的端点情况下,但在后一种情况下请引用我的服务。这可能是因为它使用了 ExposeInvocationInterceptor.currentInvocation(),并且执行另一个方法调用会弄乱它。

这是一个错误吗?基于代理的方法的一些限制?还是我必须简单地内联 MyService.aroundService

最佳答案

我重现了您的问题,并且还比较了普通 Java + AspectJ 中的类似设置(即没有 Spring 或 Spring AOP,仅使用方面切入点中使用的两个 Spring 注释)。那里不会出现问题。这是 Spring AOP 特有的东西,这是肯定的。

现在Spring使用AspectJ的切入点匹配结合自己的基于代理和委托(delegate)的AOP框架。在某个地方,这种边缘情况一定会弄乱 Spring 方面匹配的状态,从而导致您看到的行为。到目前为止我还没有调试过它,但从我现在看到的情况来看,我建议创建一个问题并查看维护人员对此有何评论。

这是我的 AspectJ MCVE证明问题不会在那里发生。顺便说一句,我不得不将包 aspect 重命名为 aop 因为在 AspectJ 中 aspect 是保留关键字。但是我也在Spring项目中重命名了它,以确保它与手头的问题无关,而且是无关的。

package aop.mcve;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
public void controllerMethod() {}
}
package aop.mcve;

import org.springframework.stereotype.Service;

@Service
public class MyService {
public Object delegateTo(MyAspect.Callable<?> callable) throws Throwable {
return callable.call();
}

public void serviceMethod() {}
}
package aop.mcve;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyAspect {
private final MyService myService = new MyService();

@Pointcut("within(aop.mcve..*) && !within(MyAspect) && execution(* *(..))")
public void inDomain() {}

@Pointcut("@target(org.springframework.stereotype.Service)")
public void inService() {}

@Pointcut("execution(* aop.mcve.MyService.*(..))")
public void inMyService() {}

@Pointcut("@target(org.springframework.web.bind.annotation.RestController)")
public void inController() {}

@Around("inDomain() && inController()")
public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("aroundController -> " + joinPoint);
return myService.delegateTo(joinPoint::proceed);
}

@Around("inDomain() && inService() && !inMyService()")
public Object aroundService(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("aroundService -> " + joinPoint);
System.out.println("You should never see this message!");
return joinPoint.proceed();
}

public interface Callable<T> {
T call() throws Throwable;
}
}
package aop.mcve;

public class AspectMcveApplication {
public static void main(String[] args) throws Throwable {
new MyService().serviceMethod();
new MyController().controllerMethod();
}
}

控制台日志:

aroundController -> execution(void aop.mcve.MyController.controllerMethod())

如您所见,建议方法 aroundService(..) 不会像在 Spring AOP 中那样被触发。


更新:我修改了您的 MCVE 以使其可与 Spring AOP 和 AspectJ 一起运行,它在 Activity 时自动检测 AspectJ 的加载时编织器。我给你发了这个pull request .

关于java - Spring AOP - 切入点仅在从 lambda 调用 joinPoint.proceed 时应用于方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64718434/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com