Многочисленные аспекты аннотации, взаимодействующие с активной цепью реактора, вызывают исключение IllegalStateException при вызове метода - PullRequest
2 голосов
/ 27 июня 2019

Я работаю над реактивным проектом Spring Web, и в настоящее время я внедряю набор различных метрик для запросов.Оказывается, наличие нескольких аннотаций @Around, взаимодействующих с объектом возврата Mono моего метода rest-controller, заставляет Spring генерировать исключение IllegalStateException.

Я использую Java 11 с пружинной загрузкой 2.1.5-RELEASE

Я прошел по пружинному коду и попытался выяснить, что именно происходит не так, и мне кажется, что при вызове продолжения () в ProceedingJoinPoint логика spring aop смешивает аргументы разных аннотаций.В частности, вызов getUserAttribute в строке AbstractApsectJAdvice 684 возвращает значение NULL и, по-видимому, имеет неверный аргумент.Я также попытался изменить порядок методов аспектов безуспешно.

Следующий метод - это рассматриваемый обработчик остатка, аннотации @TimedMono и @HostLanguageRequestCounting оба добавляют в цепочку реактора

    @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);
    }

И метод обработки аннотации HostLanguageRequestCounting:

    @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();
    }

, в котором генерируется исключение (при возврате (Mono) pjp.continue ();)

Выдается следующее исключение:

java.lang.IllegalStateException: требуется для связывания 2 аргументов, но только для 1 (JoinPointMatch НЕ было связано в вызове) в org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding (AbstractAspectJAdvice.java:605) в org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod (AbstractAspectJAdvice.jworkj.fa..a.asa.pris.aa.вызвать (AspectJAroundAdvice.java:70) в org.springframework.aop.frameРаботав моем коде.

Это настоящая ошибка весной или я что-то не так делаю?Когда я удаляю одну из аннотаций, другая выполняется без проблем.

...