我在使用spring boot和spring retry时遇到问题,在进行所有可能的尝试时未调用@Recover批注方法。

我和kotlin一起使用spring。

我的应用程序servlet容器:

class ServletInitializer : SpringBootServletInitializer() {

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

我的配置

导入org.springframework.context.annotation.Configuration
导入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("")
}

最佳答案

@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

请注意,由于没有接口(interface),Spring会创建CGLIB代理子类,因此必须将Foo及其方法设为open

08-27 23:35