Kotlin с Spring-Retry, @Recover не вызывается

У меня проблема с использованием весенней загрузки и повторной попытки пружины, метод аннотации @Recover не вызывается при выполнении всех возможных попыток.

Я использую пружину с котлином.

Контейнер сервлета My Application:

class ServletInitializer : SpringBootServletInitializer() {

    override fun configure(application: SpringApplicationBuilder) : SpringApplicationBuilder {
        return application.sources(SecurityServicesApplication::class.java)
    }
}

Моя конфигурация

import org.springframework.context.annotation.Configuration import org.springframework.retry.annotation.EnableRetry

@Configuration
@EnableRetry
class RetryConfig

Обновлено

Моя служба

import security.commons.exception.SecurityException
import org.apache.commons.lang3.exception.ExceptionUtils
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.retry.annotation.Backoff
import org.springframework.retry.annotation.Recover
import org.springframework.retry.annotation.Retryable
import org.springframework.security.oauth2.client.OAuth2RestTemplate
import org.springframework.security.oauth2.common.OAuth2AccessToken
import org.springframework.stereotype.Service
import java.net.ConnectException

@Service
class AuthorizationServerTokenRequester {

    val log = LoggerFactory.getLogger(Oauth2Service::class.java)!!

    @Value("\${accessTokenUri}")
    private val accessTokenUri: String? = null


    @Retryable(
            value = [SecurityException::class],
            maxAttemptsExpression = "\${server.oauthclient.retry.maxAttempts}",
            backoff = Backoff(delayExpression = "\${server.oauthclient.retry.delay}"))
    fun token(oauth2RestTemplate: OAuth2RestTemplate): OAuth2AccessToken? {
        try {

            return oauth2RestTemplate.accessToken
        } catch (ex: Exception) {
            if (ExceptionUtils.getRootCause(ex) is ConnectException) {
                log.error("trying again....")
            }
            throw com.security.commons.exception.SecurityException("")
        }
    }

    @Recover
    fun recover(ex: SecurityException) {
        print("##############################################################################################sssss# SecurityException")
    }
}

Мой журнал ошибок:

2018-08-10 11:28:41.802 DEBUG 40168 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : 
    Written [{timestamp=Fri Aug 10 11:28:41 BRT 2018, status=500, error=Internal Server Error, exception=org.springframework.retry.ExhaustedRetryException, 
              message=Cannot locate recovery method; nested exception is security.commons.exception.SecurityException: , 
              path=/security/api/v1/oauth2/token}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@21e2d8f6]

Решение [с помощью @Gary Russell]

Возврат метода @Recover должен быть таким же, как у метода @Retryable

fun recover(ex: S@RecoverecurityException, oauth2RestTemplate: OAuth2RestTemplate ) : OAuth2AccessToken {
    print("##############################################################################################sssss# SecurityException")
    throw br.com.totvs.security.commons.exception.SecurityException("")
}

person Estevão Jordão    schedule 10.08.2018    source источник
comment
Я думаю, что @Retryable следует использовать в интерфейсе, а не в классе   -  person lukaszrys    schedule 10.08.2018
comment
@lukaszrys Из документации находится в классе github.com/spring-projects/spring-retry, retryable работает отлично, Recover не вызывается   -  person Estevão Jordão    schedule 10.08.2018
comment
взгляните на этот ответ stackoverflow.com/a/46731031/5289288   -  person Max Farsikov    schedule 10.08.2018


Ответы (1)


@Recover методы должны иметь тот же тип возвращаемого значения, что и метод @Retryable.

ИЗМЕНИТЬ

У меня это отлично работает ...

@SpringBootApplication
@EnableRetry
public class So51787951Application {

    public static void main(String[] args) {
        SpringApplication.run(So51787951Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(Foo foo) {
        return args -> {
            try {
                foo.foo("bar");
            }
            catch (Exception e) {

            }
        };
    }

    @Bean
    public Foo foo() {
        return new Foo();
    }

}

а также

open class Foo {

    @Retryable(maxAttempts = 3)
    open fun foo(data: String) :String? {
        println(data)
        throw Exception("foo")
    }

    @Recover
    open fun rec(data: Exception) :String? {
        println("Recovered")
        return null;
    }

}

а также

bar
bar
bar
Recovered

Обратите внимание, что мне пришлось создать Foo и его методы open, потому что Spring создает подкласс прокси CGLIB, поскольку интерфейса нет.

person Gary Russell    schedule 10.08.2018
comment
это не сработало, я попробовал через интерфейс, и это тоже не сработало, я добавил свое сообщение об ошибке, уведомляющее, что метод восстановления не найден - person Estevão Jordão; 10.08.2018
comment
Извините, я не читал тип возвращаемого значения, насколько я понимаю, я закончил чтение параметра, я просто отлаживаю класс RecoverAnnotationRecoveryHandler, и на самом деле возвращаемый результат должен быть равен if (recovery! = Null && method.getReturnType (). IsAssignableFrom (failingMethod.getReturnType ())), спасибо за большое внимание и поддержку - person Estevão Jordão; 10.08.2018