Springboot Retry组件@Recover失效问题解决方法
程序员文章站
2022-03-13 09:53:05
目录背景问题复现问题解决背景在使用springboot的retry模块时,你是否出现过@recover注解失效的问题呢?下面我会对该问题进行复现,并且简要的说下解决方法。问题复现首先我们引入maven...
背景
在使用springboot的retry模块时,你是否出现过@recover注解失效的问题呢?下面我会对该问题进行复现,并且简要的说下解决方法。
问题复现
首先我们引入maven
<dependency> <groupid>org.springframework.retry</groupid> <artifactid>spring-retry</artifactid> </dependency> <dependency> <groupid>org.aspectj</groupid> <artifactid>aspectjweaver</artifactid> <version>1.9.6</version> </dependency> <dependency> <groupid>cn.hutool</groupid> <artifactid>hutool-all</artifactid> <version>5.5.2</version> </dependency> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <optional>true</optional> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
主类配置enableretry注解
package ai.guiji.csdn; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.retry.annotation.enableretry; @enableretry @springbootapplication public class csdnapplication { public static void main(string[] args) { springapplication.run(csdnapplication.class, args); } }
准备测试的retry组件类代码
package ai.guiji.csdn.component; import lombok.extern.slf4j.slf4j; import org.springframework.retry.annotation.backoff; import org.springframework.retry.annotation.recover; import org.springframework.retry.annotation.retryable; import org.springframework.stereotype.component; import java.util.function.supplier; /** @author 剑客阿良_aliang @date 2021/4/22 16:07 @description: 重试工具 */ @slf4j @component public class retryutil { @retryable( value = exception.class, maxattempts = 3, backoff = @backoff(delay = 5000, multiplier = 1.5)) public string retry(supplier<string> supplier) throws exception { string result = null; try { result = supplier.get(); } catch (exception exception) { log.error("异常报错:{}", exception.getmessage()); throw exception; } return result; } @recover public void recover(exception e) { log.error("调用超过3次异常"); } }
代码说明
1、我们可以看到retry方法会重试supplier的get结果,捕获异常并抛出异常。这里抛出后会被retry捕获并且重试。
2、maxattempts参数为重试的最大次数。
3、backoff中的delay为两次重试之间的延迟,multiplier为重试阻尼,可以这么理解,每次重试间隔时间为上一次重试间隔时间的倍数。
4、如果3次重试均抛出异常,则进入recover方法。
编写测试代码
package ai.guiji.csdn.component; import cn.hutool.core.convert.convert; import cn.hutool.http.httputil; import org.junit.jupiter.api.test; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.context.springboottest; /** @author 剑客阿良_alaing @date 2021/11/30 13:08 @description: */ @springboottest class retryutiltest { @autowired private retryutil retryutil; @test void retry() { try { system.out.println(convert.tostr(retryutil.retry(() -> httputil.post("xxxx", "")), "haha")); } catch (exception exception) { exception.printstacktrace(); } } }
执行测试结果
2021-11-30 13:37:44.012 error 13600 --- [ main] ai.guiji.csdn.component.retryutil : 异常报错:unknownhostexception: xxxx 2021-11-30 13:37:49.019 error 13600 --- [ main] ai.guiji.csdn.component.retryutil : 异常报错:unknownhostexception: xxxx 2021-11-30 13:37:58.787 error 13600 --- [ main] ai.guiji.csdn.component.retryutil : 异常报错:unknownhostexception: xxxx org.springframework.retry.exhaustedretryexception: cannot locate recovery method; nested exception is cn.hutool.core.io.ioruntimeexception: unknownhostexception: xxxx at org.springframework.retry.annotation.recoverannotationrecoveryhandler.recover(recoverannotationrecoveryhandler.java:70) at org.springframework.retry.interceptor.retryoperationsinterceptor$itemrecoverercallback.recover(retryoperationsinterceptor.java:142) at org.springframework.retry.support.retrytemplate.handleretryexhausted(retrytemplate.java:539) at org.springframework.retry.support.retrytemplate.doexecute(retrytemplate.java:387) at org.springframework.retry.support.retrytemplate.execute(retrytemplate.java:225) at org.springframework.retry.interceptor.retryoperationsinterceptor.invoke(retryoperationsinterceptor.java:116) at org.springframework.retry.annotation.annotationawareretryoperationsinterceptor.invoke(annotationawareretryoperationsinterceptor.java:163) at org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:186) at org.springframework.aop.framework.cglibaopproxy$cglibmethodinvocation.proceed(cglibaopproxy.java:750) at org.springframework.aop.framework.cglibaopproxy$dynamicadvisedinterceptor.intercept(cglibaopproxy.java:692) at ai.guiji.csdn.component.retryutil$$enhancerbyspringcglib$$d209cbc6.retry(<generated>) at ai.guiji.csdn.component.retryutiltest.retry(retryutiltest.java:17) at sun.reflect.nativemethodaccessorimpl.invoke0(native method) at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:62) at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43) at java.lang.reflect.method.invoke(method.java:498) at org.junit.platform.commons.util.reflectionutils.invokemethod(reflectionutils.java:688) at org.junit.jupiter.engine.execution.methodinvocation.proceed(methodinvocation.java:60) at org.junit.jupiter.engine.execution.invocationinterceptorchain$validatinginvocation.proceed(invocationinterceptorchain.java:131) at org.junit.jupiter.engine.extension.timeoutextension.intercept(timeoutextension.java:149) at org.junit.jupiter.engine.extension.timeoutextension.intercepttestablemethod(timeoutextension.java:140) at org.junit.jupiter.engine.extension.timeoutextension.intercepttestmethod(timeoutextension.java:84) at org.junit.jupiter.engine.execution.executableinvoker$reflectiveinterceptorcall.lambda$ofvoidmethod$0(executableinvoker.java:115) at org.junit.jupiter.engine.execution.executableinvoker.lambda$invoke$0(executableinvoker.java:105) at org.junit.jupiter.engine.execution.invocationinterceptorchain$interceptedinvocation.proceed(invocationinterceptorchain.java:106) at org.junit.jupiter.engine.execution.invocationinterceptorchain.proceed(invocationinterceptorchain.java:64) at org.junit.jupiter.engine.execution.invocationinterceptorchain.chainandinvoke(invocationinterceptorchain.java:45) at org.junit.jupiter.engine.execution.invocationinterceptorchain.invoke(invocationinterceptorchain.java:37) at org.junit.jupiter.engine.execution.executableinvoker.invoke(executableinvoker.java:104) at org.junit.jupiter.engine.execution.executableinvoker.invoke(executableinvoker.java:98) at org.junit.jupiter.engine.descriptor.testmethodtestdescriptor.lambda$invoketestmethod$6(testmethodtestdescriptor.java:210) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.jupiter.engine.descriptor.testmethodtestdescriptor.invoketestmethod(testmethodtestdescriptor.java:206) at org.junit.jupiter.engine.descriptor.testmethodtestdescriptor.execute(testmethodtestdescriptor.java:131) at org.junit.jupiter.engine.descriptor.testmethodtestdescriptor.execute(testmethodtestdescriptor.java:65) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$5(nodetesttask.java:139) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$7(nodetesttask.java:129) at org.junit.platform.engine.support.hierarchical.node.around(node.java:137) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$8(nodetesttask.java:127) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.executerecursively(nodetesttask.java:126) at org.junit.platform.engine.support.hierarchical.nodetesttask.execute(nodetesttask.java:84) at java.util.arraylist.foreach(arraylist.java:1257) at org.junit.platform.engine.support.hierarchical.samethreadhierarchicaltestexecutorservice.invokeall(samethreadhierarchicaltestexecutorservice.java:38) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$5(nodetesttask.java:143) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$7(nodetesttask.java:129) at org.junit.platform.engine.support.hierarchical.node.around(node.java:137) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$8(nodetesttask.java:127) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.executerecursively(nodetesttask.java:126) at org.junit.platform.engine.support.hierarchical.nodetesttask.execute(nodetesttask.java:84) at java.util.arraylist.foreach(arraylist.java:1257) at org.junit.platform.engine.support.hierarchical.samethreadhierarchicaltestexecutorservice.invokeall(samethreadhierarchicaltestexecutorservice.java:38) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$5(nodetesttask.java:143) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$7(nodetesttask.java:129) at org.junit.platform.engine.support.hierarchical.node.around(node.java:137) at org.junit.platform.engine.support.hierarchical.nodetesttask.lambda$executerecursively$8(nodetesttask.java:127) at org.junit.platform.engine.support.hierarchical.throwablecollector.execute(throwablecollector.java:73) at org.junit.platform.engine.support.hierarchical.nodetesttask.executerecursively(nodetesttask.java:126) at org.junit.platform.engine.support.hierarchical.nodetesttask.execute(nodetesttask.java:84) at org.junit.platform.engine.support.hierarchical.samethreadhierarchicaltestexecutorservice.submit(samethreadhierarchicaltestexecutorservice.java:32) at org.junit.platform.engine.support.hierarchical.hierarchicaltestexecutor.execute(hierarchicaltestexecutor.java:57) at org.junit.platform.engine.support.hierarchical.hierarchicaltestengine.execute(hierarchicaltestengine.java:51) at org.junit.platform.launcher.core.engineexecutionorchestrator.execute(engineexecutionorchestrator.java:108) at org.junit.platform.launcher.core.engineexecutionorchestrator.execute(engineexecutionorchestrator.java:88) at org.junit.platform.launcher.core.engineexecutionorchestrator.lambda$execute$0(engineexecutionorchestrator.java:54) at org.junit.platform.launcher.core.engineexecutionorchestrator.withinterceptedstreams(engineexecutionorchestrator.java:67) at org.junit.platform.launcher.core.engineexecutionorchestrator.execute(engineexecutionorchestrator.java:52) at org.junit.platform.launcher.core.defaultlauncher.execute(defaultlauncher.java:96) at org.junit.platform.launcher.core.defaultlauncher.execute(defaultlauncher.java:75) at com.intellij.junit5.junit5ideatestrunner.startrunnerwithargs(junit5ideatestrunner.java:69) at com.intellij.rt.junit.ideatestrunner$repeater.startrunnerwithargs(ideatestrunner.java:33) at com.intellij.rt.junit.junitstarter.preparestreamsandstart(junitstarter.java:230) at com.intellij.rt.junit.junitstarter.main(junitstarter.java:58) caused by: cn.hutool.core.io.ioruntimeexception: unknownhostexception: xxxx at cn.hutool.http.httprequest.send(httprequest.java:1153) at cn.hutool.http.httprequest.execute(httprequest.java:969) at cn.hutool.http.httprequest.execute(httprequest.java:940) at cn.hutool.http.httputil.post(httputil.java:216) at cn.hutool.http.httputil.post(httputil.java:197) at ai.guiji.csdn.component.retryutiltest.lambda$retry$0(retryutiltest.java:17) at ai.guiji.csdn.component.retryutil.retry(retryutil.java:22) at ai.guiji.csdn.component.retryutil$$fastclassbyspringcglib$$a565f63f.invoke(<generated>) at org.springframework.cglib.proxy.methodproxy.invoke(methodproxy.java:218) at org.springframework.aop.framework.cglibaopproxy$cglibmethodinvocation.invokejoinpoint(cglibaopproxy.java:779) at org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:163) at org.springframework.aop.framework.cglibaopproxy$cglibmethodinvocation.proceed(cglibaopproxy.java:750) at org.springframework.retry.interceptor.retryoperationsinterceptor$1.dowithretry(retryoperationsinterceptor.java:93) at org.springframework.retry.support.retrytemplate.doexecute(retrytemplate.java:329) ... 73 more caused by: java.net.unknownhostexception: xxxx at java.net.abstractplainsocketimpl.connect(abstractplainsocketimpl.java:184) at java.net.plainsocketimpl.connect(plainsocketimpl.java:172) at java.net.sockssocketimpl.connect(sockssocketimpl.java:392) at java.net.socket.connect(socket.java:589) at java.net.socket.connect(socket.java:538) at sun.net.networkclient.doconnect(networkclient.java:180) at sun.net.www.http.httpclient.openserver(httpclient.java:463) at sun.net.www.http.httpclient.openserver(httpclient.java:558) at sun.net.www.http.httpclient.<init>(httpclient.java:242) at sun.net.www.http.httpclient.new(httpclient.java:339) at sun.net.www.http.httpclient.new(httpclient.java:357) at sun.net.www.protocol.http.httpurlconnection.getnewhttpclient(httpurlconnection.java:1220) at sun.net.www.protocol.http.httpurlconnection.plainconnect0(httpurlconnection.java:1156) at sun.net.www.protocol.http.httpurlconnection.plainconnect(httpurlconnection.java:1050) at sun.net.www.protocol.http.httpurlconnection.connect(httpurlconnection.java:984) at sun.net.www.protocol.http.httpurlconnection.getoutputstream0(httpurlconnection.java:1334) at sun.net.www.protocol.http.httpurlconnection.getoutputstream(httpurlconnection.java:1309) at cn.hutool.http.httpconnection.getoutputstream(httpconnection.java:451) at cn.hutool.http.httprequest.sendformurlencoded(httprequest.java:1176) at cn.hutool.http.httprequest.send(httprequest.java:1145) ... 86 more process finished with exit code 0
并没有进入recover方法,注解未触发。
问题解决
这里有个很容易忽视的点,就是retry方法是有返回值的,所以recover方法也必须是相同类型带返回值的方法。所以要把recover方法改一下。
package ai.guiji.csdn.component; import lombok.extern.slf4j.slf4j; import org.springframework.retry.annotation.backoff; import org.springframework.retry.annotation.recover; import org.springframework.retry.annotation.retryable; import org.springframework.stereotype.component; import java.util.function.supplier; /** @author 剑客阿良_aliang @date 2021/4/22 16:07 @description: 重试工具 */ @slf4j @component public class retryutil { @retryable( value = exception.class, maxattempts = 3, backoff = @backoff(delay = 5000, multiplier = 1.5)) public string retry(supplier<string> supplier) throws exception { string result = null; try { result = supplier.get(); } catch (exception exception) { log.error("异常报错:{}", exception.getmessage()); throw exception; } return result; } @recover public string recover(exception e) { log.error("调用超过3次异常"); return "调用超过3次异常"; } }
重新执行测试看下结果
以上就是springboot retry组件@recover失效问题解决方法的详细内容,更多关于springboot retry 解决@recover失效的资料请关注其它相关文章!