传送门

Spring Cloud Alibaba系列之nacos:(1)安装

Spring Cloud Alibaba系列之nacos:(2)单机模式支持mysql

Spring Cloud Alibaba系列之nacos:(3)服务注册发现

Spring Cloud 系列之OpenFeign:(4)集成OpenFeign

从一个实际问题出发

一个微服务如何调用多个不同Feign接口?

用不同的name属性来区分不同的目标服务

回顾一下声明OpenFeign接口,里面提到微服务auth调用cipher的接口。

要调用远程feign接口,需要先按照feign接口定义,比如前面的:

@FeignClient(name = FeignConstant.CIPHER_SERVICE)
public interface AuthFeignClient
{@GetMapping(value = "/echo/{str}")String echo(@PathVariable("str") String str);
}
  • 接口上面打上注解@FeignClient,其中FeignClient表明这是一个OpenFeign接口,里面至少要定义属性"name",对应的所要调用的服务的名称
  • 声明要调用的方法,与传统的SpringMvc没有区别

如果现在微服务auth调用其它模块的接口呢?假设现在有另一个日志模块log-service

那么该怎么调用呢?首先要定义定义OpenFeign接口!从上面的原有接口来看

@FeignClient(name = FeignConstant.CIPHER_SERVICE)
public interface AuthFeignClient
{  }

因为AuthFeignClient接口上面要引入FeignClient注解,里面name定义了目标微服务的名称"cipher-service",由此显而易见,一个接口上只能定义一个目标服务,所以对于log-service只能新建一个接口LogFeignClient

public class FeignConstant
{/** 加密服务 */public static final String CIPHER_SERVICE = "cipher-service";/** 日志服务 */public static final String LOG_SERVICE = "log-service";
}@FeignClient(name = FeignConstant.LOG_SERVICE)
public interface LogFeignClient
{
}

并在此基础上,新增一个log模块,并同样定义一个接口供auth模块调用

@RestController
public class LogController
{@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)public String echo(@PathVariable String string){return "Hello Nacos Discovery " + string;}
}

就差一个测试类了,在auth模块新增测试方法echoLog()如下

@RestController
public class TestController
{@Autowiredprivate LogFeignClient logFeignClient;@RequestMapping(value = "/log/echo/{str}", method = RequestMethod.GET)public String logEcho(@PathVariable String str){return logFeignClient.echo(str);}}

浏览器请求一下,http://localhost:8080/log/echo/ssss,返回Hello Nacos Discovery ssss,表明调用成功

相同的name属性,不同的contextId来区分不同的目标服务

上面对于cipher,log服务,在auth端FeignClient定义中是用不同的name来区分的。但是这样配置取决代码组织。如果所有的FeignClient是相同的名称remote-auth-call,表示远程调用。我们来试试:

@FeignClient(name = FeignConstant.CIPHER_SERVICE, path = FeignConstant.CIPHER_SERVICE)
public interface AuthFeignClient
{@GetMapping(value = "/echo/{str}")String echo(@PathVariable("str") String str);
}@FeignClient(name = FeignConstant.CIPHER_SERVICE, path = FeignConstant.LOG_SERVICE)
public interface LogFeignClient
{@GetMapping(value = "/log/echo/{str}")String echo(@PathVariable("str") String str);
}
  • AuthFeignClient,LogFeignClient的name名称是一样的,通过path指定服务名称 

启动一下auth,很不幸会报错

The bean 'cipher-service.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

这个办法可以通过指定contextId来指定

If we want to create multiple feign clients with the same name or url so that they would point to the same server but each with a different custom configuration then we have to use contextId attribute of the @FeignClient in order to avoid name collision of these configuration beans.

具体的解决方案可以参考Spring Cloud OpenFeign

配置URL直连调用

FeignClient支持客户端指定微服务调用地址url,这个功能在开发时特别有用。现代稍微大一点的项目,几乎都是多人协作开发,开发过程中,如果需要本地调试debug,通过配置url就显得很方便

@FeignClient(name = FeignConstant.LOG_SERVICE, url = "127.0.0.1:8083")
public interface LogFeignClient
{@GetMapping(value = "/log/echo/{str}")String echo(@PathVariable("str") String str);
}

使用SpringCloud的框架开发,一般都会用到注册发现中心,不论是官方的Eureka还是阿里的Nacos。假设张三,李四,王五同时开发一个项目,大家都启动时都会注册到Nacos(或Eureka),如果不配置url直接调用,张三本地debug时很有可能调用到其它人的机器上导致失败。

超时处理

OpenFeign组件支持配置接口调用超时!可以直接看下官方文档的说明,这里配上了中文翻译

We can configure timeouts on both the default and the named client. OpenFeign works with two timeout parameters:

  • connectTimeout prevents blocking the caller due to the long server processing time.

  • readTimeout is applied from the time of connection establishment and is triggered when returning the response takes too long.

我们可以在默认客户端和命名客户端上配置超时。OpenFeign使用两个超时参数:

  • connectTimeout防止由于服务器处理时间过长而阻塞调用者。
  • readTimeout从连接建立时开始应用,并在返回响应时间过长时触发。

配置超时时间

首先在auth端的配置文件中bootstrap.properties添加上面的超时设置

feign.client.config.default.connectTimeout=1000
feign.client.config.default.readTimeout=1000

请求读取超时时间readTimeout

然后将log服务的接口改造下,手动让它休眠超过1s,比如3s钟

@RestController
public class LogController
{@RequestMapping(value = "/log/echo/{string}", method = RequestMethod.GET)public String echo(@PathVariable String string) throws Exception{Thread.sleep(3 * 1000);return "Hello Nacos Discovery " + string;}
}

浏览器请求一下,http://localhost:8080/log/echo/ssss,返回错误页面

通过浏览器抓取一下请求,会发现整个请求才耗时1s钟,说明客户端设置的超时时间readTimeout生效了!

请求连接超时时间connectTimeout

上面的readTimeout表示请求已经到达服务端,但是响应超过了规定时间没有返回。而connectTimeout表示客户端跟服务器建立连接的超时时间,这里要注意一点的是connectTimeout要设置的不合理,可能并不能生效从而导致设置的回调处理失败,后面会具体例子介绍

In case the server is not running or available a packet results in connection refused. The communication ends either with an error message or in a fallback. This can happen before the connectTimeout if it is set very low. The time taken to perform a lookup and to receive such a packet causes a significant part of this delay. It is subject to change based on the remote host that involves a DNS lookup.

如果服务器未运行或不可用,数据包将导致连接被拒绝。通信以错误消息或回退结束。如果connectTimeout设置得很低,则这可能会在connectTimeout之前发生。执行查找和接收这样的分组所花费的时间导致了该延迟的很大一部分。它可能会根据涉及DNS查找的远程主机进行更改。

在系统中设置超时时间是很有必要的,如果没有或设置了不合理的超时时间,可能会导致系统的RT变高,严重时甚至系统会不可用。所以可以在很多地方:db数据源连接,httpclient调用,java的try...lock方法等都有超时设置的支持

日志处理

如果按照上面的顺序一路执行下来,细心的会发现一个问题,在远程调用时,auth后端服务并没有打印任何日志。 这里不是说程序员主动打印的业务日志,而是OpenFeign组件自带的日志。为了达到打印OpenFeign日志的目的,需要做以下处理

配置Feign调用的日志级别为DEBUG

先需要将指定的Feign接口配置日志级别为DEBUG

logging.level.project.user.UserClient: DEBUG

这里的project.user.UserClient指的就是系统里面FeignClient接口路径,比如调用log服务的feignClietn接口LogFeignClient

# feign log
logging.level.com.tw.tsm.auth.feign.LogFeignClient=DEBUG

如果有多个FeignClient,可以通过通配符来来指定,而不用一个个都列出来

logging.level.com.tw.tsm.auth.feign.*=DEBUG

增加OpenFeign配置类,指定打印的日志级别为FULL

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfiguration
{@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}

经过上面的2步之后,浏览器请求一下,http://localhost:8080/log/echo/ssss,观察一下控制台日志,会输出类似以下日志

2023-02-11 20:31:57.450 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] ---> GET http://log-service/log/echo/ssss HTTP/1.1
2023-02-11 20:31:57.451 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] ---> END HTTP (0-byte body)
2023-02-11 20:32:00.460 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] <--- HTTP/1.1 200 (3009ms)
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] connection: keep-alive
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] content-length: 26
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] content-type: text/plain;charset=UTF-8
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] date: Sat, 11 Feb 2023 12:32:00 GMT
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] keep-alive: timeout=60
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo]
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] Hello Nacos Discovery ssss
2023-02-11 20:32:00.461 DEBUG 8012 --- [nio-8080-exec-3] com.tw.tsm.auth.feign.LogFeignClient     : [LogFeignClient#echo] <--- END HTTP (26-byte body)

从日志中可以看到

  • 请求类型,为GET
  • 请求URL, http://log-service/log/echo/ssss,里面包括了请求参数ssss
  • 返回响应Hello Nacos Discovery ssss
  • 以及请求的时间等等

日志的级别含义

如果要指明日志打印的详细程度,可以通过Logger.Level来指定。在刚才的例子中是配置的FULL,表示的打印所有的请求,包括:记录请求和响应的标头、正文和元数据。除此以外,还有其它三种

  1. NONE,默认的级别,表示不打印
  2. BASIC,仅记录请求方法和URL以及响应状态代码和执行时间
  3. HEADERS,记录基本信息以及请求和响应标头

OpenFeign 降级

OpenFeign 支持对服务降级的(可以参考1.5. Feign Spring Cloud CircuitBreaker Support),不过由于引入的版本是最新的,已经默认不支持Hystrix了(可以参考1.4. Feign Hystrix Support)

If Spring Cloud CircuitBreaker is on the classpath and spring.cloud.openfeign.circuitbreaker.enabled=true, Feign will wrap all methods with a circuit breaker.

所以手动引入hystrix 项目的依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><exclusions><!-- 移除Ribbon负载均衡器,避免冲突 --><exclusion><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-netflix-ribbon</artifactId></exclusion></exclusions></dependency>

降级处理

OpenFeign支持回调函数,比如改造上面的LogFeignClient,增加降级配置fallback

@FeignClient(name = FeignConstant.LOG_SERVICE, fallback = LogFeignClientFallback.class)
public interface LogFeignClient
{@GetMapping(value = "/log/echo/{str}")String echo(@PathVariable("str") String str);
}

而fallback对应的LogFeignClientFallback,就是LogFeignClient远程feign调用失败后执行的函数

@Component
public class LogFeignClientFallback implements LogFeignClient {@Overridepublic String echo(String str) {return "fail";}
}

通过上面配置的超时例子测试一下, 浏览器请求一下,http://localhost:8080/log/echo/ssss,返回“fail”字符串,实现了服务的降级了,更多用法可以参考文档研究一下

继承支持

通过对openFeign的介绍及使用的例子,现在已经能感受到它的方便了。那还能再方便一点吗?可以的,OpenFeign官方支持feign接口的继承特性Feign Inheritance Support,以便进一步简化它的调用,具体什么意思呢?还是以上面的例子来说明!

按照前面调用的关系,现在的类图应该是下面这样的

那么这个类图的问题在于哪里呢?

  • 对于每一个feignClient接口,除了要在调用方声明,比如请求URL,请求方式,请求参数
  • 还必须要在被调用方,也同样声明一遍

为此,OpenFeign提供了继承特性,就是将接口声明从调用方抽象出来,让被调用方直接实现该接口来达到减化编码的目的,现在改造一下上面的AuthFeignClient

增加openFeign接口模块feign-api,及下面的cipher-api和log-api

然后将原来auth-service下面定义的删除,引入cipher-api模块

<dependency><groupId>com.tw.tsm</groupId><artifactId>cipher-api</artifactId><version>0.0.1-SNAPSHOT</version></dependency>

在cipher-service模块改造一下原来的Controller,让实现CipherFeignClient,并移除RequestMapping配置信息

@RestController
public class EchoController implements CipherFeignClient
{public String echo(@PathVariable String string){return "Hello Nacos Discovery " + string;}}

重新发起调用会发现效果是一样,这样就达到了利用feign接口定义的目的

Spring Cloud 系列之OpenFeign:(5)OpenFeign的高级用法相关推荐

  1. 【Java开发】Spring Cloud 05 :远程服务调用Openfeign 替代 WebClient

    在前边章节中,我们借助 Nacos 的服务发现能力,使用 WebClient 实现了服务间调用.从功能层面上来讲,我们已经完美地实现了微服务架构下的远程服务调用,但是从易用性的角度来看,这种实现方式似 ...

  2. 【小马哥】Spring Cloud系列讲座

    这里推荐一个不错的Spring Cloud系列讲座,讲师简介如下: 小马哥,阿里巴巴技术专家,从事十余年Java EE 开发,国内微服务技术讲师.目前主要负责微服务技术推广.架构设计.基础设施.迁移等 ...

  3. Spring Cloud系列勘误

    Spring Cloud系列已经写完了,这是一系列的学习笔记,由于写作匆忙,难免会有出错的文字或者代码,实在抱歉. 目前作者已经发现了几处有错误的地方,为了小伙伴们在学习的过程中不陷入泥淖,我将已发现 ...

  4. Spring Cloud 系列之 Netflix Ribbon 负载均衡

    什么是 Ribbon Ribbon 是一个基于 HTTP 和 TCP 的 客服端负载均衡工具,它是基于 Netflix Ribbon 实现的. 它不像 Spring Cloud 服务注册中心.配置中心 ...

  5. Spring Cloud 系列之 Netflix Zuul 服务网关(三)

    本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Netflix Zuul 服务网关(一) Spring Cloud 系列之 Netflix Zuul 服务网关(二) ...

  6. Spring Cloud系列之Spring Cloud Config

    认识Spring Cloud Config Spring Cloud Config是最早的配置中心,虽然后面的之秀Nacos可以取代它, 但是Spring Cloud Config还是很多公司在用,比 ...

  7. Spring cloud系列十二 监控Hystrix界面:Hystrix dashboard 和 Turbine

    1. 概述 为了更好的监控Hystrix的性能,Spring Cloud提供Hystrix dashboard和Turbin来达到这个目的. Hystrix dashboard可以实时监控Hystri ...

  8. java小马哥百度网盘_小马哥spring boot和spring cloud系列

    资源内容: 小马哥spring boot和spring cloud系列|____小马哥 Java 微服务实践 - Spring Boot 系列          |____pptx           ...

  9. 小马哥java_小马哥 Java 微服务实践 - Spring Cloud 系列

    资源内容: 小马哥 Java 微服务实践 - Spring Cloud 系列|____Java 微服务实践 - Spring Cloud系列(四)服务发现注册.wmv|____Java 微服务实践 - ...

最新文章

  1. CVPR 2022 | 室外多模态3D目标检测(DeepFusion)
  2. 信号与系统作业问题回复
  3. oracle xe 连接数据库,【Oracle XE系列之二】PLSQL Developer 远程连接Oracle XE数据库-Go语言中文社区...
  4. shell + mysql
  5. ORB-SLAM2中生成金字塔提取FAST角点和计算BRIEF描述子
  6. Android之tint图片着色器
  7. UDP 通讯协议 局域网通信发送消息 简单实现
  8. 名校博士被撤销学位,只因7行文字抄袭及1张互联网图片​……
  9. RocketMQ架构
  10. mysql数据库基础知识和安装与卸载(快速入门)
  11. Android 8.0 的部分坑及对应解决方法
  12. android excel读取和写入_Python科普帖 csv amp; excel
  13. 手贱拆笔记本清灰记录
  14. 分布式事务解决方案之可靠消息最终一致性
  15. cv2.cvtColor报错
  16. API是什么?API的基础知识你知道多少
  17. (1)桌面客制化之单屏幕修改以及wight修改
  18. REMIX编译DeclarationError: Identifier already declared
  19. 去除html双击后选中有蓝色背景
  20. Pr入门系列之十五:校色与调色

热门文章

  1. 个人公众号历史文章合集
  2. 【树莓派不吃灰】兄弟连篇⑥ Linux系统进程管理
  3. 有关研究生如何进行科研的研究
  4. [雷神] =总结=视音频编解码技术零基础学习方法
  5. 【如何和陌生人攀上关系?】
  6. 360安全浏览器如何使用网络收藏夹
  7. 怎么还原计算机系统还原,电脑如何一键还原,小编教你电脑怎么还原系统
  8. 阿里、百度、搜狐等公司社招面试记录与总结(转)
  9. 用python实现PDF转word
  10. Java静态类 Builder(建造者)模式