SpringCloud OpenFeign超时控制示例详解

 更新时间:2024年05月27日 09:35:48   作者:Ken_1115  
在Spring Cloud中使用OpenFeign时,可以通过配置来控制请求的超时时间,这篇文章主要介绍了SpringCloud OpenFeign超时控制,需要的朋友可以参考下

前言:

在上一章节中我们简单的介绍了如何使用OprnFeign去调用微服务,因为消费侧和服务侧是两个不同的微服务,这样可能会出现超时的现象,例如服务侧需要3秒处理任何才能返回结果,但消费侧可能2秒就断开连接了,这时就会因为时间差而出现连接超时的问题,而本节内容则是关于如果去对OpenFeign进行超时控制。

1、编写代码模拟连接超时

(1)编写providder-payment8001项目PaymentController类的代码

package com.ken.springcloud.controller;
import com.ken.springcloud.entities.CommonResult;
import com.ken.springcloud.entities.Payment;
import com.ken.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;
    @Value("${server.port}")
    private String serverPort;
    @Resource
    private DiscoveryClient discoveryClient;
    @PostMapping("/payment/insert")
    public CommonResult insert(@RequestBody Payment payment) {
        int result = paymentService.insert(payment);
        log.info("插入结果{}",result);
        if(result > 0) {
            return new CommonResult(200,"插入数据库成功,提供服务的端口号为" + serverPort,result);
        }else {
            return new CommonResult(500,"插入数据库失败",result);
        }
    }
    @GetMapping("/payment/get/{id}")
    public CommonResult insert(@PathVariable("id") Long id) {
        Payment payment = paymentService.getPaymentById(id);
        log.info("查询结果{}",payment);
        if(payment != null) {
            return new CommonResult(200,"查询成功,提供服务的端口号为" + serverPort,payment);
        }else {
            return new CommonResult(500,"没有对应的数据,查询失败,查询id" + id,payment);
        }
    }
    @GetMapping("/payment/discovery")
    public Object discovery() {
        //获取eureka内的服务
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("***service:" + service);
        }
        //获取服务名为CLOUD-PAYMENT-SERVICE下的实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
        }
        return this.discoveryClient;
    }
    @GetMapping("/payment/lb")
    public String getPaymentLB() {
        //返回当前服务的端口号
        return serverPort;
    }
    @GetMapping("/payment/feign/timeout")
    public String paymentFeigntimeout() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //返回当前服务的端口号
        return serverPort;
    }
}

(2)编写cloud-consumer-feign-order80项目PaymentFeignService类的代码

package com.ken.springcloud.service;
import com.ken.springcloud.entities.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
//这里@FeignClient里写的是指定要访问的微服务的名称,表示通过FeignClient去Eureka上面找名称为CLOUD-PAYMENT-SERVICE的微服务的接口
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    //指明要调用的CLOUD-PAYMENT-SERVICE的微服务的接口,这里调用的是PaymentController类里的/payment/get/{id}接口
    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id);
    @GetMapping("/payment/feign/timeout")
    public String paymentFeigntimeout();
}

(3)编写cloud-consumer-feign-order80项目OrderFeignController的代码

package com.ken.springcloud.controller;
import com.ken.springcloud.entities.CommonResult;
import com.ken.springcloud.entities.Payment;
import com.ken.springcloud.service.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Slf4j
@RestController
public class OrderFeignController {
    @Resource
    private PaymentFeignService paymentFeignService;
    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        return paymentFeignService.getPaymentById(id);
    }
    @GetMapping("/payment/feign/timeout")
    public String paymentFeigntimeout() {
        //客户端一般默认等待1秒钟
        return paymentFeignService.paymentFeigntimeout();
    }
}

2、测试payment接口是否正常工作

分别启动eureka-server7001、eureka-server7002,然后再启动provider-payment8001,最后再启动cloud-consumer-feign-order80,全部启动完毕后在浏览器的地址栏里输入http://localhost:8001/payment/feign/timeout 并且回车调用接口,最后可以看到接口调用成功并返回8001,这证明provider-payment8001服务工作正常

3、测试通过consumer服务远程调用payment服务

在浏览器地址栏里输入http://localhost/consumer/payment/feign/timeout 并且回车调用接口,这时会显示Read timed out executing GET http://CLOUD-PAYMENT-SERVICE/payment/feign/timeout的错误信息,这是因为Feign客户端默认只等待一秒钟,但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错,为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。

效果图:

4、设置Feign客户端的超时时间

修改cloud-consumer-feign-order80项目的application.yml文件(因为OpenFeign集成了Ribbon,所以OpenFeign的超时控制也由最底层的Ribbon来进行限制,所以这里是对Ribbon进行配置)

集成示意图:

application.yml文件

server:
  port: 80
eureka:
  client:
    #表示是否将自己注册进Eureka Server里,默认为true
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

5、重新测试通过consumer服务远程调用payment服务

重新启动consumer服务,然后重新用浏览器调用http://localhost/consumer/payment/feign/timeout 接口,发现现在并不会再次发生微服务间调用出现连接超时的情况

到此这篇关于SpringCloud OpenFeign超时控制的文章就介绍到这了,更多相关SpringCloud OpenFeign超时控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis之GEO存储地理位置信息的使用

    Redis之GEO存储地理位置信息的使用

    在外卖软件中的附近的美食店铺、外卖小哥的距离,打车软件附近的车辆,交友软件中附近的小姐姐。我们都可以利用redis的GEO地理位置计算得出。本文就来详细的介绍一下
    2021-10-10
  • Linux中JDK安装配置教程

    Linux中JDK安装配置教程

    这篇文章主要为大家详细介绍了Linux中JDK安装配置教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • java实现读取txt文件并以在每行以空格取数据

    java实现读取txt文件并以在每行以空格取数据

    今天小编就为大家分享一篇java实现读取txt文件并以在每行以空格取数据,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Java中的system.getProperty()的作用及使用方法

    Java中的system.getProperty()的作用及使用方法

    System.getProperty() 方法用于获取系统属性的值,该方法接受一个字符串参数,表示要获取的系统属性的名称,返回值为字符串类型,表示该属性的值,接下来通过本文给大家介绍Java中的system.getProperty()的作用及使用方法,感兴趣的朋友跟随小编一起看看吧
    2023-05-05
  • SpringBoot之导入静态资源详解

    SpringBoot之导入静态资源详解

    今天带大家学习SpringBoot导入静态资源的过程,文中介绍的非常详细,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • Intellij IDEA神器居然还有这些小技巧

    Intellij IDEA神器居然还有这些小技巧

    Intellij IDEA真是越用越觉得它强大,它总是在我们写代码的时候,不时给我们来个小惊喜,本文给大家主要介绍一些你可能不知道的但是又实用的小技巧,感兴趣的朋友跟随小编一起看看吧
    2021-01-01
  • SpringBoot+thymeleaf+ajax实现局部刷新详情

    SpringBoot+thymeleaf+ajax实现局部刷新详情

    这篇文章主要介绍了SpringBoot+thymeleaf+ajax实现局部刷新详情,文章围绕主题展开详细的内容介绍具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • 在Java中使用日志框架log4j的方法

    在Java中使用日志框架log4j的方法

    Log4j有三个主要的组件/对象:Loggers(记录器),Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出,今天通过本文给大家分享Java日志框架log4j的相关知识,感兴趣的朋友一起看看吧
    2021-08-08
  • Spring注解@Qualifier的详细用法你知道几种

    Spring注解@Qualifier的详细用法你知道几种

    本文给大家分享Spring注解@Qualifier的详细用法,包括@Autowired和@Resource区别介绍,本文通过示例代码给大家详细介绍,感兴趣的朋友跟随小编一起看看吧
    2021-07-07
  • 源码解析springbatch的job运行机制

    源码解析springbatch的job运行机制

    这篇文章主要介绍了springbatch的job是如何运行的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08

最新评论