②SpringCloud 实战:引入Feign组件,完善服务间调用
这是SpringCloud实战系列中第二篇文章,了解前面第一篇文章更有助于更好理解本文内容:
①SpringCloud 实战:引入Eureka组件,完善服务治理
简介
Feign 是一个声明式的 REST 客户端,它的目的就是让 REST 调用更加简单。
Feign 提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。
而且 Feign 会完全代理 HTTP 请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Spring Cloud 对 Feign 进行了封装,使其支持 SpringMVC 标准注解和 ttpMessageConverters。Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡,与 Hystrix 组合使用,支持熔断回退。
如果你没有使用 Spring Cloud,那么可以直接用原生的 Feign 来调用 API,如果你使用了 Spring Cloud,可以直接用 Spring Cloud OpenFeign 来调用 API。
使用原生API
这里以官方给出的Github示例为例,展示怎么使用原生的API来发起请求
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
@RequestLine("POST /repos/{owner}/{repo}/issues")
void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo);
}
public static class Contributor {
String login;
int contributions;
}
public class MyApp {
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
// 调用接口,接收返回参数
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
// 打印输出结果
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
}
上面的代码是一个 GET 请求的示列,定义了一个 GitHub 的接口,接口中定义了一个查询的方法和创建Issue的方法。
在方法上使用了@RequestLine 注解,定义了请求方法类型和请求的 URI,URI 中有对应的参数占位符,返回值有集合,集合中是对应的结构对象。
最后通过 Feign 的 builder 模式构建了 GitHub 接口对象后,就可以直接通过 GiuHub 接口对象调用里面的 contributors 方法。
支持的注解
@RequestLine
作用与方法上;定义请求,支持用大括号{expression}包装对应@Param注释参数。
使用示例:
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
@Param
作用于参数上;定义模板变量参数映射,代码示例同上。@Headers
作用于类上或者方法上;定义请求头Header,代码示例:@Headers("Accept: application/json")
interface BaseApi<V> {
@Headers("Content-Type: {contentType}")
@RequestLine("PUT /api/{key}")
void put(@Param("key") String key, V value,@Param("contentType") String type);
}
@QueryMap
作用于参数上;定义name-value对的映射(POJO),以展开为查询字符串,代码示例:public interface Api {
@RequestLine("GET /find")
V find(@QueryMap Map<String, Object> queryMap);
@RequestLine("GET /findObj")
V findObj(@QueryMap CustomPojo customPojo);
}
@HeaderMap
作用于参数上;映射成HeaderMap,代码示例:public interface Api {
@RequestLine("POST /")
void post(@HeaderMap Map<String, Object> headerMap);
}
@Body
作用于参数上;定义一个模版,定义一个模版,解析对应的表达式,代码实例:@RequestLine("POST /")
@Headers("Content-Type: application/xml")
@Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")
void xml(@Param("user_name") String user, @Param("password") String password); @RequestLine("POST /")
@Headers("Content-Type: application/json")
// json curly braces must be escaped!
@Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
void json(@Param("user_name") String user, @Param("password") String password);
使用OpenFeign
原生的Feign API 使用已经很方便了,但是还有更简单的,惊不惊喜意不意外?Spring Cloud 推出了spring-cloud-openfeign,使用OpenFeign比使用原生的API还要简单。
先创建一个提供服务的项目:[eureka-provider](http://jinglingwang.cn)
具体的步骤和上一篇文章创建Eureka-Client 一模一样,有变动的配置:
server.port = 8082
spring.application.name=eureka-provider
eureka.instance.appname=eureka-provider
编写提供服务接口
@Controller
public class HelloController{
@ResponseBody
@RequestMapping(method = RequestMethod.GET, path = "hello")
public String hello(){
return "hello, my name is eureka provider!";
}
}
启动服务,观察provider成功注册到注册中心

我们把之前的Eureka-Client 作为消费者,使用OpenFeign来调用刚刚创建的provider项目。
现在开始改造Eureka-Client 项目:
引入 spring-cloud-openfeign 组件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类上添加注解
@EnableFeignClients,启用Feign的客户端功能定义Feign接口,@FeignClient 注解指定了服务名称
@FeignClient(value = "eureka-provider")
public interface ProviderFeign{
/**
* 调用 eureka-provider 的 hello 接口
* @return
*/
@RequestMapping("/hello")
String hello();
}
定义sayHello接口,通过feign调用provider的接口
@RestController
public class SayHelloController{
@Autowired
private ProviderFeign providerFeign;
@GetMapping("sayHello")
public String sayHello(){
return providerFeign.hello();
}
}
重启Eureka-Client 项目,访问http://localhost:8081/sayHello。页面显示
hello, my name is eureka provider!表示我们使用OpenFeign发起服务间调用成功。
至此一个简单使用OpenFeign发起服务间的调用示例就完成了,下面的教程是进阶版,了解一下还是非常有必要的。
使用OpenFeign的其他小技巧
Get 请求以对象作为参数提交
当服务提供者定义了一个Get请求的接口,参数是一个对象,比如这样的:
@RequestMapping(method = RequestMethod.GET, path = "query")
public String query(UserDTO user){
当服务调用方Feign使用@QueryMap来进行接口调用
@RequestMapping("/query")
String query(@QueryMap UserDTO userDTO);
这时候会发生服务提供方接收到的请求变为Post的现象,服务提供者接收到的请求报错信:
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
这种问题怎么解决呢?
把@QueryMap 注解换成
@SpringQueryMap注解就可以,这是最简单快速的解决办法。在@RequestMapping注解中加入consumes的属性
在依赖中加入feign-httpclient包,之后在@RequestMapping注解中配置consumes属性@GetMapping(value = "/query",consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
把Feign 默认的 Client 替换成OKHttp
Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,我们可以把它换成httpclient或者OkHttp,添加如下配置即可:
# 启用okhttp
feign.okhttp.enabled=true
feign.httpclient.enabled=false
如果你不是用的spring-cloud-dependencies,或者里面没有okhttp的包,自己引入即可:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
配置Feign日志输出
FeignClient 有一个属性configuration,我们可以通过这个属性来自定义每个FeignClient的日志输出
新建一个配置类ProviderFeignConfiguration:
import feign.Logger;
...
@Configuration
public class ProviderFeignConfiguration{
@Bean
public Logger.Level loggerLevel(){
return Logger.Level.BASIC;
}
}
Feign日志记录的级别一共有4种:NONE、BASIC、HEADERS、FULL;
为@FeignClient指定配置
@FeignClient(value = "eureka-provider",configuration = ProviderFeignConfiguration.class)
为FeignClient包所在位置单独配置日志隔离级别
logging.level.cn.jinglingwang.eurelaclient.demo.feign=DEBUG
这一步你也可以不这样做,可以通过自定义继承 feign.Logger 重写log方法即可输出日志。
重启项目,访问接口http://localhost:8081/sayHello,查看日志输出变化:
DEBUG 20000 --- [nio-8081-exec-4] c.j.e.demo.feign.ProviderFeign : [ProviderFeign#hello] ---> GET http://eureka-provider/hello HTTP/1.1
DEBUG 20000 --- [nio-8081-exec-4] c.j.e.demo.feign.ProviderFeign : [ProviderFeign#hello] <--- HTTP/1.1 200 (4ms)
配置Auth认证
Feign提供了一个默认的拦截器BasicAuthRequestInterceptor,他主要的功能是为发起的Http请求添加一个请求头:template.header("Authorization", headerValue);
使用方法:
在刚刚上面的ProviderFeignConfiguration类里面添加以下代码即可:
@Bean
public BasicAuthRequestInterceptor basicAuth(){
return new BasicAuthRequestInterceptor("username","jinglingwang.cn");
}
改造下provider的接口代码,输出Header看是否能输出这个字段
@ResponseBody
@RequestMapping(method = RequestMethod.GET, path = "hello")
public String hello(HttpServletRequest request) throws UnsupportedEncodingException{
String header = request.getHeader("Authorization");
if(header != null && header.length() > 6){
String authorization = new String(Base64.decode(header.substring(6).getBytes("UTF-8")),"UTF-8");
System.out.println(authorization);
}
return "hello, my name is eureka provider!";
}
重启两个项目,访问http://localhost:8081/sayHello,查看provider控制台成功输出以下内容:
username:jinglingwang.cn
配置超时时间
在刚刚上面的ProviderFeignConfiguration类里面添加以下代码:
@Bean
public Request.Options options(){
return new Request.Options(5,TimeUnit.SECONDS,5,TimeUnit.SECONDS,true);
}
上面参数分别的意思是:连接超时5秒,读取超时5秒,true:遵循3xx重定向
通过配置文件配置Feign
上面的配置基本上都是通过Java代码的方式来进行的,其实也可以通过配置文件来配置Feign,通过feign.client.config.{feignName}.xxx 来进行配置,比如:
# 单独配置Feing:eureka-provider的连接超时时间 1ms
feign.client.config.eureka-provider.read-timeout=1
重启之后刷新接口http://localhost:8081/sayHello,出现超时的日志:

具体可以配置的配置项见下图:

注意:配置文件配置的优先级是大于上面Java代码配置的优先级的,从上面的测试结果也可以看出,因为我们同时使用了两种配置方式(重启时Java 的配置并没有注释),从下图所示的源码也可以看出:

总结
- Feign 支持原生的API和声明式注解两种方式发起请求
- 启用Feign客户端需要使用
@EnableFeignClients注解来开启 - FeignClient 支持配置文件和Java配置来控制,配置文件的优先级更高
②SpringCloud 实战:引入Feign组件,完善服务间调用的更多相关文章
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-01 常用的服务间调用方式讲解
笔记 第四章 服务消费者ribbon和feign实战和注册中心高可用 1.常用的服务间调用方式讲解 简介:讲解常用的服务间的调用方式 RPC: 远程过程调用,像调用本地 ...
- SpringCloud微服务服务间调用之OpenFeign介绍
开发微服务,免不了需要服务间调用.Spring Cloud框架提供了RestTemplate和FeignClient两个方式完成服务间调用,本文简要介绍如何使用OpenFeign完成服务间调用. Op ...
- SpringCloud初体验:三、Feign 服务间调用(FeignClient)、负载均衡(Ribbon)、容错/降级处理(Hystrix)
FeignOpenFeign Feign是一种声明式.模板化的HTTP客户端. 看了解释过后,可以理解为他是一种 客户端 配置实现的策略,它实现 服务间调用(FeignClient).负载均衡(Rib ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-04 高级篇幅之服务间调用之负载均衡策略调整实战
笔记 4.高级篇幅之服务间调用之负载均衡策略调整实战 简介:实战调整默认负载均衡策略实战 自定义负载均衡策略:http://cloud.spring.io/spring-cloud-stati ...
- spring cloud服务间调用feign
参考文章:Spring Cloud Feign设计原理 1.feign是spring cloud服务间相互调用的组件,声明式.模板化的HTTP客户端.类似的HttpURLConnection.Apac ...
- SpringCloud实现服务间调用(RestTemplate方式)
上一篇文章<SpringCloud搭建注册中心与服务注册>介绍了注册中心的搭建和服务的注册,本文将介绍下服务消费者调用服务提供者的过程. 本文目录 一.服务调用流程二.服务提供者三.服务消 ...
- Istio实践(2)-流量控制及服务间调用
前言:接上一篇istio应用部署,本文介绍通过virtualservice实现流量控制,并通过部署client端进行服务调用实例 1. 修改virtualservice组件,实现权重占比访问不同版本服 ...
- Asp.Net Core使用SignalR进行服务间调用
网上查询过很多关于ASP.NET core使用SignalR的简单例子,但是大部分都是简易聊天功能,今天心血来潮就搞了个使用SignalR进行服务间调用的简单DEMO. 至于SignalR是什么我就不 ...
- 基于gin的golang web开发:服务间调用
微服务开发中服务间调用的主流方式有两种HTTP.RPC,HTTP相对来说比较简单.本文将使用 Resty 包来实现基于HTTP的微服务调用. Resty简介 Resty 是一个简单的HTTP和REST ...
随机推荐
- Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析
一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...
- 双非本科拿到阿里腾讯字节,分享Java后端路线
前言 最近有很多小师妹来问我. 师妹:师兄~看了你之前的从腾讯到阿里,最后选择字节,觉得你特别厉害,请问你是怎么进BAT的呀,能不能告诉我你的学习路线呀~ 既然小师妹都这么问了,那我在这篇就如实回答她 ...
- socket 参考文档
socket.io 中文手册,socket.io 中文文档转载于:http://www.cnblogs.com/xiezhengcai/p/3956401.html 服务端 io.on('connec ...
- 删除指定路径下指定天数之前(以文件的最后修改日期为准)的文件:BAT + VBS
代码如下: @echo off ::演示:删除指定路径下指定天数之前(以文件的最后修改日期为准)的文件. ::如果演示结果无误,把del前面的echo去掉,即可实现真正删除. ::本例调用了临时VBS ...
- Python爬虫实战详解:爬取图片之家
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 如何使用python去实现一个爬虫? 模拟浏览器请求并获取网站数据在原始数据 ...
- 基于uni-app的微信小程序之分包
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 0. 缘由 1. 关于分包 1.0 这是 官方文档 1.1 注意事项 2.使用方法 2.1 首先你得有个uniapp的微信小程序项目 2.2 ...
- 833. Find And Replace in String —— weekly contest 84
Find And Replace in String To some string S, we will perform some replacement operations that replac ...
- UOJ Round总结
#22. [UR #1]外星人 一开始随便搞出第一问答案,很显然的性质对$x$有变化的$a$一定是递减的,就拿一个桶直接记录可以达到的值 然后我开始想第二问,一开始想直接在这个桶上统计答案,然后发现不 ...
- 一步一步实现直播软件源码的RTMP推流流媒体服务
第一步:准备工具 OBS推流工具下载及配置可以参见:OBS推流工具 第二步:安装流媒体服务 Windows/Linux系统环境中搭建直播流媒体服务 极速安装,下载解压一键启动即可,支持Windows和 ...
- 转载:Pycharm的常用快捷键
一直想着找一下pycharm的快捷键,但是每次都忘记找了,这次刚好碰到一个很全的,就直接借用别人的来当作自己的笔记ba 转载来源:https://www.cnblogs.com/liangmingsh ...