Spring AOP在单一连接点(JoinPoint)上使用多个带绑定的Around切面方法(advice)时报错

发布于 2022-09-11 14:43:47 字数 1614 浏览 26 评论 0

在一个方法上使用2个注解,并用两个不同的切面分别去处理这两个注解中的值,连接点方法如下所示:

@CacheFetch(cacheName = CacheManager.CACHE_DATASOURCE_INFO)
@TenantAware(method = OperationMethod.OPERATION, operation = OperationType.GET)
public DataSourceInfo fetchDataSource(String sourceId) {...}

切面方法1:

@Around("within(com.xx.yy.zz..*) && @annotation(fetch)")
public Object fetchFromCache(ProceedingJoinPoint pjp, CacheFetch fetch) throws Throwable {...}

切面方法2:

@Around("isXXX() && @annotation(tenantAware)")
public Object handleTenantAware(ProceedingJoinPoint pjp, TenantAware tenantAware) throws Throwable {...}

两个切面方法写在了2个不同的Aspect类中,并实现了Ordered接口。当执行到切入点方法时,报出以下错误:

java.lang.IllegalStateException: Required to bind 2 arguments, but only bound 1 (JoinPointMatch was NOT bound in invocation)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding(AbstractAspectJAdvice.java:591)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671)

如果移除其中掉一个方法的注解,则另一个切面方法可以正常执行。网上搜索内容很少,相关的只有很老的Spring版本中有人问到。

使用的Spring版本为4.1.6,尝试升级到4.1.9 或4.3.20问题仍然存在。

按我的理解这样写应该没有什么问题,但不知为何报错还没人提出,不确定是bug还是用法问题。希望有人能帮忙,多谢!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半衾梦 2022-09-18 14:43:47

挖,跟随源码很容易可以发现,在两个指定了不同@Order后,代理的顺序被明显的区分出来。而代理后的方法没有注解,导致第二个切面参数个数不匹配。

  • 两个改进方案:(前提是一定需要指定切面顺序,且想使用注解切面)

    1. 切点的匹配方式不使用@annotation,使用其他方式匹配到切点,使用反射获取注解内容;
    2. 在一个方法上只使用一个切面注解(这些注解最好能单独维护一个类,用于切面排序)
@Component
public class ReportCron implements ReportCronService {
    // 注入『自己』,方便引用自己的方法时也进入切面
    // 注入自己时,不能直接注入自己,可以注入接口形式
    @Autowired
    ReportCronService service;
    @MyAnnotation_1()
    public void xxx() {
        service.yyy();
    }
    @MyAnnotation_2()
    @Override
    public void yyy() {
        // TODO 业务逻辑
    }  
}
聊慰 2022-09-18 14:43:47

你的问题在于利用了注解的形式@annotation(tenantAware)")去获取参数,在只切一次的情况下没有问题,但是切面嵌套就不行了,你可以利用传统的方式去获取这个tenantAware就行了。

安静被遗忘 2022-09-18 14:43:47

如果是实现了Ordered接口,它默认值如下。

public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE + 1;
}

如果是两个Ordered的话,拦截器估计不能判断谁优先, @Order 时可指定一个int型的value属性,该属性值越小,则优先级越高。
例如:

@Aspect
@Order(1)
public class AspectFirst {
}

@Aspect
@Order(2)
public class AspectSecond {
}

你试试看

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文