Spring Cloud Feign 例子(日志,局部超时,失败断容,脱离SpringCloud使用Feign)

依赖

    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
    implementation 'io.github.openfeign:feign-okhttp'

properties配置


全局超时
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

针对第三方接口超时 
hystrix.command.IService#QueryAll(Integer,String).execution.isolation.thread.timeoutInMilliseconds=20000

config配置

@Configuration // 扫包目录下此注解 为全局配置
public class FeignConfig {

    private static final int TIME_OUT = 55;

    @Bean
    public okhttp3.OkHttpClient okHttpClient(CQInterceptor cqInterceptor) {
        Logger logger = LoggerFactory.getLogger(OkHttpClient.class);
        HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(logger::info);
        logInterceptor.level(HttpLoggingInterceptor.Level.BODY);
        return new OkHttpClient.Builder()
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                .addInterceptor(cqInterceptor)//自定义拦截器
                .addInterceptor(logInterceptor)//注入日志拦截
                .build();
    }

    @Bean
    public CQInterceptor cqInterceptor() {
        return new CQInterceptor();
    }


    @Bean
    public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

}

自定义拦截器

public class CQInterceptor implements Interceptor {
    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";

    @Value(value = "${auth.authKey}")
    private String authKey;

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();


        boolean isCQRequest = chain.request().url().pathSegments().contains("mock");

        if (isCQRequest) {

            if (METHOD_GET.equals(request.method())) {
                //如果是get请求
                HttpUrl newUrl = request.url().newBuilder()
                        .addEncodedQueryParameter("authKey", authKey)
                        .build();
                request = request.newBuilder()
                        .url(newUrl).build();
            } else if (METHOD_POST.equals(request.method())) {

                HttpUrl newUrl = request.url().newBuilder()
                        .addEncodedQueryParameter("authKey", authKey)
                        .build();
                request = request.newBuilder()
                        .url(newUrl).build();
            }
        }
        log.info("Hey there, this is my CQ-request: " + request);
        Response response = chain.proceed(request);
        if (isCQRequest) {
            String contentType = response.header("content-type");
            if (StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) {
                okhttp3.MediaType mediaType = okhttp3.MediaType.parse(contentType);
                String content = response.body().string();
                ResponseBody responseBody = ResponseBody.create(JSONUtils.recursive(content).toString(), mediaType);
                response = response.newBuilder().body(responseBody).build();
            }
        }

        log.info("Hey there, this is my CQ-response: " + response);
        return response;
    }


}

IService类

@FeignClient(name = "api-service", url = "${demo.baseUrl}", path = "", fallbackFactory = DemoFallbackFactory.class)
public interface IService{


    @GetMapping(value = "/demo")
    JsonResult<String> queryAll(@RequestParam(name = "IdNumber") Integer IdNumber, @RequestParam(name = "IdType") String IdType);


}

DemoFallbackFactory 用于生成fallback类示例,

@Component
@Slf4j
public class DemoFallbackFactory implements FallbackFactory<IService> {

    private static JsonResult serviceNotFoundError() {
        return JsonResult.ret(ResultType.DATA_NO_CONNECTIONINFO);
    }

    @Override
    public IService create(Throwable cause) {
        Throwable rootCause = ExceptionUtils.getRootCause(cause);
        if (rootCause instanceof ClientException) {
            String msg = ((ClientException) rootCause).getErrorMessage();
            if (StringUtils.startsWith(msg, "Load balancer does not have available server for client")) {
                String client = msg.replace("Load balancer does not have available server for client:", "");
                log.error("服务 {} 未启动", client);
            }
        } else {
            log.error("服务调用失败", cause);
        }
        return (IService) Enhancer.create(IService.class, (MethodInterceptor) (o, method, objects, methodProxy) -> serviceNotFoundError());
    }

}

Spring boot 使用 Feign 脱离 Spring Cloud Feign

修改 config配置 新增

    @Resource
    private Encoder feignFormEncoder;

    @Resource
    private Decoder feignDecoder;

    @Resource
    private LoadBalancerClient loadBalancerClient;

    @Bean
    public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    @Bean
    public Decoder feignDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new SpringDecoder(messageConverters);
    }


    @Bean
    IService iService(){
        loadBalancerClient.choose("WX-MPS").getHost(); //此方法是获取其他微服务Feign的url ,可用于将本地微服务接口 换成 普通接口 ,获取其他微服务host port 作用
        return Feign.builder()
                .client(new feign.okhttp.OkHttpClient(okHttpClient))
                .encoder(feignFormEncoder)
                .decoder(feignDecoder)
                .options(new Request.Options(2000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3))
                .contract(new SpringMvcContract())// 加入这个可以可以继续使用@GetMapping之类的接口
                .target(IService .class, url);
    }

注释掉 FeignClient 接口

//@FeignClient(name = "api-service", url = "${demo.baseUrl}", path = "", fallbackFactory = DemoFallbackFactory.class)
public interface IService{


    @GetMapping(value = "/demo")
    JsonResult<String> queryAll(@RequestParam(name = "IdNumber") Integer IdNumber, @RequestParam(name = "IdType") String IdType);


}

调用方法 不变

@RestController
public class QueryController {

    @Resource
    private IService iService;

    @GetMapping(value = "/QueryPersonId")
    public JsonResult queryPersonId(@RequestParam("IdNumber") Integer IdNumber, @RequestParam(value = "IdType", defaultValue = "C1") String IdType) {
        JsonResult<String> stringJsonResult = iService.queryAll(IdNumber, IdType);
        Assert.state(stringJsonResult.isSuccessful(), stringJsonResult.getMsg());
        return JsonResult.success(stringJsonResult.getObj());
    }

展开阅读全文
©️2020 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值