使用 Spring AOP 时,在单个连接点上具有参数绑定的多个 Around 建议会导致错误
Multiple Around advices with argument binding on a single join point causes error when using Spring AOP
我在一个方法上写了 2 个注释和 2 个 Around 建议来处理每个注释值。
连接点方法是这样的:
@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 {...}
这两个建议的区别是Aspect 类 和Aspect 类 都实现了Ordered 接口。程序执行到fetchDataSource连接点方法时,出现异常:
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,问题依旧。
恕我直言,上面的代码应该可以工作,而且我自己也没有发现任何错误。我不确定这是一个错误还是其他我不知道的东西。任何帮助将不胜感激。谢谢。
问题已解决,但仍有疑问。
我正在使用 2 方面 类,顺序设置为 Ordered.HIGHEST_PRECEDENCE
和 Ordered.LOWEST_PRECEDENCE
。如果我将订单值 Ordered.HIGHEST_PRECEDENCE
替换为另一个值,错误就会消失。很奇怪的现象,异常显示与实际原因无关。有谁知道真正的原因吗?
这是由于ExposeInvocationInterceptor not load firstly, and it will cause userAttributes不会通过Spring Bean(for CacheFetch
)注入参数造成的。
您还可以在 :
中找到 comment
No MethodInvocation found: Check that an AOP invocation is in progress,
and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically,
note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!
还有一个 issue 尝试使用 PriorityOrdered
来解决这个问题,但它似乎仍然没有进行。
所以对于你的问题,有两种方案可以解决:
把Ordered
改成HIGHEST_PRECEDENCE
,也许HIGHEST_PRECEDENCE+1
通过ApplicationContext.getBean
手动注入bean
我发现另一种情况可能会使 Exposeinvocationinterceptor
中的调用无效,导致 org.springframework.aop.aspectj.aspectjexpressionpointcut ා matches (java.lang.reflect.method, java.lang.class <? >, Java. Lang.Object...)
无法获得有效的方法调用。
具体情况:当有多个切面时,当一个高优先级的切面异步处理时joinpoint.Processed()
,下一个切面会切换到新的线程,所以无法获取到ThreadLocal变量。
我在一个方法上写了 2 个注释和 2 个 Around 建议来处理每个注释值。
连接点方法是这样的:
@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 {...}
这两个建议的区别是Aspect 类 和Aspect 类 都实现了Ordered 接口。程序执行到fetchDataSource连接点方法时,出现异常:
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,问题依旧。
恕我直言,上面的代码应该可以工作,而且我自己也没有发现任何错误。我不确定这是一个错误还是其他我不知道的东西。任何帮助将不胜感激。谢谢。
问题已解决,但仍有疑问。
我正在使用 2 方面 类,顺序设置为 Ordered.HIGHEST_PRECEDENCE
和 Ordered.LOWEST_PRECEDENCE
。如果我将订单值 Ordered.HIGHEST_PRECEDENCE
替换为另一个值,错误就会消失。很奇怪的现象,异常显示与实际原因无关。有谁知道真正的原因吗?
这是由于ExposeInvocationInterceptor not load firstly, and it will cause userAttributes不会通过Spring Bean(for CacheFetch
)注入参数造成的。
您还可以在 :
中找到 commentNo MethodInvocation found: Check that an AOP invocation is in progress,
and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically,
note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!
还有一个 issue 尝试使用 PriorityOrdered
来解决这个问题,但它似乎仍然没有进行。
所以对于你的问题,有两种方案可以解决:
把
Ordered
改成HIGHEST_PRECEDENCE
,也许HIGHEST_PRECEDENCE+1
通过
ApplicationContext.getBean
手动注入bean
我发现另一种情况可能会使 Exposeinvocationinterceptor
中的调用无效,导致 org.springframework.aop.aspectj.aspectjexpressionpointcut ා matches (java.lang.reflect.method, java.lang.class <? >, Java. Lang.Object...)
无法获得有效的方法调用。
具体情况:当有多个切面时,当一个高优先级的切面异步处理时joinpoint.Processed()
,下一个切面会切换到新的线程,所以无法获取到ThreadLocal变量。