SpringCloud OpenFeign超时控制示例详解
作者:Ken_1115
前言:
在上一章节中我们简单的介绍了如何使用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超时控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!