Kotlin with Spring-重试未调用的@Recover
Kotlin with Spring-Retry the @Recover not called
我在使用 spring 引导和 spring 重试时遇到问题,在进行所有可能的尝试时都没有调用 @Recover 注释方法。
我正在使用 spring 和 kotlin。
我的应用程序 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方法的return必须和@Retryable方法一样
fun recover(ex: S@RecoverecurityException, oauth2RestTemplate: OAuth2RestTemplate ) : OAuth2AccessToken {
print("##############################################################################################sssss# SecurityException")
throw br.com.totvs.security.commons.exception.SecurityException("")
}
@Recover
方法必须与 @Retryable
方法具有相同的 return 类型。
编辑
这对我来说很好...
@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 代理子类。
我在使用 spring 引导和 spring 重试时遇到问题,在进行所有可能的尝试时都没有调用 @Recover 注释方法。
我正在使用 spring 和 kotlin。
我的应用程序 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方法的return必须和@Retryable方法一样
fun recover(ex: S@RecoverecurityException, oauth2RestTemplate: OAuth2RestTemplate ) : OAuth2AccessToken {
print("##############################################################################################sssss# SecurityException")
throw br.com.totvs.security.commons.exception.SecurityException("")
}
@Recover
方法必须与 @Retryable
方法具有相同的 return 类型。
编辑
这对我来说很好...
@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 代理子类。