我正在从事Spring Web反应项目,目前正在实现针对请求的不同指标的收集。事实证明,与我的rest-controller方法的Mono返回对象进行交互的多个@Around注释会导致Spring引发IllegalStateException。
我正在将Java 11与Spring Boot 2.1.5-RELEASE一起使用
我逐步浏览了Spring代码,并试图找出到底出了什么问题,在我看来,当在ProceedingJoinPoint上调用proce()时,spring aop逻辑会混淆不同批注的参数。具体来说,AbstractApsectJAdvice行684中的getUserAttribute调用返回null,并且似乎提供了错误的参数。我还尝试过更改方面方法的顺序,但没有成功。
以下方法是有问题的其余处理程序,@TimedMono和@HostLanguageRequestCounted批注都添加到了反应堆链中
@Counted("statistics_incoming_requests")
@TimedMono("statistics_incoming_requestExecutionTime")
@PostMapping("/translate/{id}/{field}")
@HostLanguageRequestCounted("statistics_incoming_hostLanguageRequestCount")
public Mono<TranslationResponseBody> getTranslation(@PathVariable String id,
@PathVariable String field,
@RequestBody TranslationRequestBody requestBody) {
return translateService.translate(id, requestBody.getTargetLanguage(), requestBody.getText(), field);
}
这是处理TimedMono批注的方法:
@Around(value = "@annotation(timed)")
@Order(2)
@SuppressWarnings("checkstyle:illegalThrows")
public Mono<?> timeExecution(ProceedingJoinPoint pjp, TimedMono timed) throws Throwable {
Long tStart = System.nanoTime();
Object m = pjp.proceed();
long tEnd = System.nanoTime();
if (!(m instanceof Mono)) {
throw (new Exception("Method must return a mono object"));
}
Mono<?> mono = (Mono) m;
Consumer<Object> stopTimer = obj -> {
meterRegistry.timer(timed.value())
.record(tEnd - tStart, TimeUnit.NANOSECONDS);
};
return mono.doOnError(stopTimer).doOnNext(stopTimer);
}
以及处理HostLanguageRequestCounted批注的方法:
@Around(value = "@annotation(hostLanguageRequestCounted)")
@Order(1)
public Object gatherTenantMetrics(ProceedingJoinPoint pjp,
HostLanguageRequestCounted hostLanguageRequestCounted) throws Throwable {
Optional<TranslationRequestBody> body = HostLanguageRequestCountedMetricAspect
.getArgumentOfType(TranslationRequestBody.class, pjp);
return Mono.subscriberContext()
.flatMap(ctx -> {
log.info(ctx.toString());
return Mono.just(ctx.get("host"));
}).flatMap(host -> {
if (host != null && body.isPresent() && body.get().getTargetLanguage() != null) {
String metricKey = hostLanguageRequestCounted.value();
metricKey += "_" + host.toString().toLowerCase();
metricKey += "_" + body.get().getTargetLanguage().toLowerCase();
meterRegistry.counter(metricKey).increment();
}
try {
return (Mono<?>) pjp.proceed();
} catch (Throwable t) {
return Mono.error(t);
}
});
}
private static <T> Optional<T> getArgumentOfType(Class<T> clazz, ProceedingJoinPoint pjp) {
return Arrays.stream(pjp.getArgs())
.filter((arg) -> clazz.isAssignableFrom(arg.getClass()))
.map((obj) -> (T) obj).findFirst();
}
在其中引发异常(返回(单声道)pjp.proceed();)
引发的异常如下:
java.lang.IllegalStateException:需要绑定2个参数,但仅绑定1个(在调用中未绑定JoinPointMatch) 在org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding(AbstractAspectJAdvice.java:605) 在org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) 在org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) 在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) 在org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
堆栈跟踪中的下一个条目是我的代码行。
这是春季的实际错误,还是我做错了什么?当我删除其中一个注释时,另一个注释将没有问题地执行。