捕获异常假装



我想处理来自假装客户端的任何异常,即使服务不可用。但是我无法使用try/catch来捕获它们。这是我的假客户端:

@FeignClient(name = "api-service", url ="localhost:8888")
public interface ClientApi extends SomeApi {
}

其中 api 是:

@Path("/")
public interface SomeApi {
@GET
@Path("test")
String getValueFromApi();
}

客户端与 try/catch 的用法:

@Slf4j
@Service
@AllArgsConstructor
public class SampleController implements SomeApi {
@Autowired
private final ClientApi clientApi;
@Override
public String getValueFromApi() {
try {
return clientApi.getValueFromApi();
} catch (Throwable e) {
log.error("CAN'T CATCH");
return "";
}
}
}

依赖项在版本中:

  • 弹簧引导 2.2.2.发布
  • 春天的云霍克斯顿.SR1

代码应该按照如何管理假装错误?工作。

我收到了一些长堆栈跟踪,其中异常是:

  1. 原因:java.net.Connect异常:连接被拒绝(连接被拒绝(
  2. 原因:假装。可重试异常:连接被拒绝(连接被拒绝(执行 GET http://localhost:8888/test
  3. 原因:com.netflix.hystrix.exception.HystrixRuntimeException:ClientApi#getValueFromApi(( 失败,没有可用的回退。

如何正确捕获Feign exptions,即使客户端服务(在本例中为localhost:8888(不可用?

附言。当假装客户端服务可用时,它可以工作,好的。我只关注例外方面。

处理服务不可用情况的更好方法是使用断路器模式。幸运的是,使用 Netflix Hystrix 作为断路器模式的实现很容易。

首先,您需要在应用程序配置中为假客户端启用 Hystrix。

应用程序.yml

feign:
hystrix:
enabled: true

然后,您应该为指定的假客户端接口编写一个回退类。 在这种情况下getValueFormApi回退类中的方法将主要类似于您编写catch块(电路处于打开状态且不会尝试原始方法的情况除外(。

@Component
public class ClientApiFallback implements ClientApi {
@Override
public String getValueFromApi(){
return "Catch from fallback";
}
}

最后,您只需要为假客户端指定回退类。

@FeignClient(name = "api-service", url ="localhost:8888", fallback = ClientApiFallback.class)
public interface ClientApi extends SomeApi {
}

这样,您的方法getValueFromApi是故障安全的。如果 出于任何原因,任何未捕获的异常都会从getValueFromApi调用ClientApiFallback方法进行转义。

若要启用断路器并配置应用程序以处理意外错误,需要:

1.- 使能断路器本身

@SpringBootApplication
@EnableFeignClients("com.perritotutorials.feign.client")
@EnableCircuitBreaker
public class FeignDemoClientApplication {

2.- 创建你的后备 bean

@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PetAdoptionClientFallbackBean implements PetAdoptionClient {
@Setter
private Throwable cause;
@Override
public void savePet(@RequestBody Map<String, ?> pet) {
log.error("You are on fallback interface!!! - ERROR: {}", cause);
}
}

回退实现时必须记住的一些事项:

  • 必须标记为@Component,它们在整个应用程序中是唯一的。
  • 回退 Bean 应该有一个原型作用域,因为我们希望为每个异常创建一个新的作用域。
  • 使用构造函数注入进行测试。

3.- 您的错误解码器,根据返回的 HTTP 错误实现回退启动:


public class MyErrorDecoder implements ErrorDecoder {
private final ErrorDecoder defaultErrorDecoder = new Default();
@Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
return new MyCustomBadRequestException();
}
if (response.status() >= 500) {
return new RetryableException();
}
return defaultErrorDecoder.decode(methodKey, response);
}
}

4.- 在你的配置类中,将重试器和错误解码器添加到 Spring 上下文中:


@Bean
public MyErrorDecoder myErrorDecoder() {
return new MyErrorDecoder();
}
@Bean
public Retryer retryer() {
return new Retryer.Default();
}

您还可以向重试程序添加自定义:


class CustomRetryer implements Retryer {
private final int maxAttempts;
private final long backoff;
int attempt;
public CustomRetryer() {
this(2000, 5); //5 times, each 2 seconds
}
public CustomRetryer(long backoff, int maxAttempts) {
this.backoff = backoff;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
public void continueOrPropagate(RetryableException e) {
if (attempt++ >= maxAttempts) {
throw e; 
}
try {
Thread.sleep(backoff);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
@Override
public Retryer clone() {
return new CustomRetryer(backoff, maxAttempts);
}
}

如果您想获得有关如何在应用程序中实现 Feign 的功能示例,请阅读本文。

相关内容

  • 没有找到相关文章

最新更新