1 整合hystrix实现异常回调
hystrix是于熔断、降级等的组件,在springboot中可以很容易的FeignClient进行整合从而实现异常回调和处理。
依赖引入:
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
开启hystrix组件功能:在启动类上添加该注解,用于开启Hystrix的功能
@EnableHystrix // 该注解上已经添加有 @EnableCircuitBreaker
开启Feign和hystrix的整合:在application.properties中添加(整合Feign和Hystrix的关键,否则可能导致异常回调功能不生效)
#开启feignClient和hystrix的整合,@EnableCircuitBreaker 注解是单独开启服务熔断降级,而没有和feignClient整合
#所以添加@EnableCircuitBreaker并不能是FeignClient的fallBack生效
feign.hystrix.enabled=true
1.1 FallBack回调类实现
FeignClient代码和配置:使用fallBack属性,定义fallback实现类
import com.alibaba.fastjson.JSONObject;
import com.htb.thirdclient.fallback.BaiDuCollectClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "baiDuCollectClient", url = "http://data.zz.baidu.com", fallback = BaiDuCollectClientFallback.class)
public interface BaiDuCollectClient {
@PostMapping("/urls?site={site}&token={token}")
JSONObject send(@PathVariable("site")String site, @PathVariable("token")String token, String url);
}
BaiDuCollectClientFallback 代码实现:(这种方式无法在回调中获取到异常信息)
import com.alibaba.fastjson.JSONObject;
import com.htb.thirdclient.BaiDuCollectClient;
import org.springframework.stereotype.Component;
/**
* FeignClient+Hystrix整合异常回调实现类示例
* 缺点:这种方式无法获取到异常信息
*/
@Component
public class BaiDuCollectClientFallback implements BaiDuCollectClient {
@Override
public JSONObject send(String site, String token, String url) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", "调用异常了");
return jsonObject;
}
}
1.2 FallBackFactory回调工厂类实现
FeignClient代码和配置:使用fallbackFactory 参数,实现FallbackFactory接口
import com.alibaba.fastjson.JSONObject;
import com.htb.thirdclient.fallback.BaiDuCollectClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "baiDuCollectClient", url = "http://data.zz.baidu.com", fallbackFactory = BaiDuCollectClientFallbackFactory.class)
public interface BaiDuCollectClient {
@PostMapping("/urls?site={site}&token={token}")
JSONObject send(@PathVariable("site")String site, @PathVariable("token")String token, String url);
}
BaiDuCollectClientFallbackFactory代码实现:(这种方式可以获取到具体的异常信息)
import com.alibaba.fastjson.JSONObject;
import com.htb.thirdclient.BaiDuCollectClient;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* FeignClient+Hystrix整合异常回调工厂示例
* 优点:这种方式可以获取到具体的异常信息
*/
@Component
public class BaiDuCollectClientFallbackFactory implements FallbackFactory<BaiDuCollectClient> {
@Override
public BaiDuCollectClient create(Throwable throwable) {
return new BaiDuCollectClient() {
@Override
public JSONObject send(String site, String token, String url) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("site", site);
jsonObject.put("url", url);
jsonObject.put("error", throwable.getMessage());
return jsonObject;
}
};
}
}
2 自定义异常处理配置
FeignClient代码和配置:
import com.alibaba.fastjson.JSONObject;
import com.htb.thirdclient.baidu.BaiDuFeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(value = "baiDuCollectClient", url = "http://data.zz.baidu.com", configuration = BaiDuFeignConfig.class)
public interface BaiDuCollectClient {
@PostMapping("/urls?site={site}&token={token}")
JSONObject send(@PathVariable("site")String site, @PathVariable("token")String token, String url);
}
BaiDuFeignConfig实现:
import feign.codec.ErrorDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BaiDuFeignConfig {
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}
自定义异常处理:CustomErrorDecoder
package com.htb.thirdclient.baidu;
import feign.Response;
import feign.codec.ErrorDecoder;
import feign.Util;
import java.io.IOException;
import org.springframework.http.HttpStatus;
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
String body = "";
try {
if (response.body() != null) {
body = Util.toString(response.body().asReader());
}
} catch (IOException e) {
// 处理读取响应体时的异常
e.printStackTrace();
}
HttpStatus status = HttpStatus.valueOf(response.status());
switch (status) {
case BAD_REQUEST:
return new BadRequestException("Bad request error: " + body);
case NOT_FOUND:
return new NotFoundException("Resource not found: " + body);
case INTERNAL_SERVER_ERROR:
return new InternalServerErrorException("Internal server error: " + body);
default:
return new GeneralFeignException("General error: " + body, response.status());
}
}
// 自定义异常类
public static class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
public static class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}
public static class InternalServerErrorException extends RuntimeException {
public InternalServerErrorException(String message) {
super(message);
}
}
public static class GeneralFeignException extends RuntimeException {
private final int status;
public GeneralFeignException(String message, int status) {
super(message);
this.status = status;
}
public int getStatus() {
return status;
}
}
}
评论区