目录
1 RPC和HTTP
1.1 RPC是什么
1.2 RPC的主要实现
1.3 RPC的网络通讯协议
1.4 RPC的数据传输格式
1.5 RPC框架有哪些
1.6 RPC调用过程示意图
1.7 Http是什么
1.8 RPC框架有哪些
1.9 Http调用过程示意图
1.10 RPC和Http的相同点和不同点
1.11 RPC和Http对比
1.12 使用场景:
2 OpenFeign
2.1 什么是Feign
2.2 什么是OpenFeign
2.3 常用注解
2.4 Feign和OpenFeign的相同点
2.5 Feign和OpenFeign的区别
2.6 OpenFeign超时处理
2.7 OpenFeign日志增强
2.8 小结
3 RestTemplate
3.1 GET请求
getForEntity
getForObject
3.2 POST请求
postForEntity
postForObject
postForLocation
3.3 put请求
3.4 delete请求
3.5 通用方法exchange
3.6 总结
RestTemplate和OpenFeign的区别:
RPC:Remote Procedure Call(远程过程调用) 是一个计算机通信协议,这个协议允许运行于一台计算机的程序调用另一台计算机的子程序,程序员不用再为这个交互编写程序;
类似的是RMI(Remote Methods Invoke 远程方法调用)
RPC强调的是过程调用,调用的过程对用户而言是应该是透明的,用户不用去关心调用的细节,可以像调用本地服务一样调用远程服务;所以RPC一定要对调用的过程进行封装;
RPC采用的是TCP作为底层的传输协议
两个程序间进行通讯,必须要约定好数据传输格式,必须定义好请求和响应的格式。
数据在网络中传输需要进行序列化,所以需要约定统一的序列化方式。
RPC框架有:dubbo、webservice(cxf)、hessian(RMI远程方法调用,比较轻量)
http其实是一种网络传输协议,基于TCP,规定了数据传输的格式,现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。
http框架有:httpClient
相同点
底层通讯都是基于socket,都可以实现远程调用,都可以实现服务间调用;
不同点:
效率要求高,开发过程使用统一,可以使用RPC;
需要灵活,跨语言、跨平台,可以使用Http
一般来讲,微服务强调的是独立、自治、灵活。而RPC方式的限制较多,因此微服务框架中,一般都会采用基于Http的Rest风格服务。
Netflix Feign 是 Netflix 公司发布的一种实现负载均衡和服务调用的开源组件。Spring Cloud 将其与 Netflix 中的其他开源服务组件(例如 Eureka、Ribbon 以及 Hystrix 等)一起整合进 Spring Cloud Netflix 模块中,整合后全称为 Spring Cloud Netflix FeignFeign 对 Ribbon 进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。
Feign 是一种声明式服务调用组件,它在 RestTemplate 的基础上做了进一步的封装。通过 Feign,我们只需要声明一个接口并通过注解进行简单的配置(类似于 Dao 接口上面的 Mapper 注解一样)即可实现对 HTTP 接口的绑定。通过 Feign,我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用。
Feign 支持多种注解,例如 Feign 自带的注解以及 JAX-RS 注解等,但遗憾的是 Feign 本身并不支持 Spring MVC 注解,这无疑会给广大 Spring 用户带来不便。
2019 年 Netflix 公司宣布 Feign 组件正式进入停更维护状态,于是 Spring 官方便推出了一个名为 OpenFeign 的组件作为 Feign 的替代方案。
OpenFeign 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件,它的出现就是为了替代进入停更维护状态的 Feign。
OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持,例如 @RequestMapping、@GetMapping 和 @PostMapping 等。
注解 | 说明 |
---|---|
@FeignClient | 该注解用于通知 OpenFeign 组件对 @RequestMapping 注解下的接口进行解析,并通过动态代理的方式产生实现类,实现负载均衡和服务调用。 |
@EnableFeignClients | 该注解用于开启 OpenFeign 功能,当 Spring Cloud 应用启动时,OpenFeign 会扫描标有 @FeignClient 注解的接口,生成代理并注册到 Spring 容器中。 |
@RequestMapping | Spring MVC 注解,在 Spring MVC 中使用该注解映射请求,通过它来指定控制器(Controller)可以处理哪些 URL 请求,相当于 Servlet 中 web.xml 的配置。 |
@GetMapping | Spring MVC 注解,用来映射 GET 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.GET) 。 |
@PostMapping | Spring MVC 注解,用来映射 POST 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.POST) 。 |
Feign 和 OpenFeign 都是 Spring Cloud 下的远程调用和负载均衡组件。
Feign 和 OpenFeign 作用一样,都可以实现服务的远程调用和负载均衡。
Feign 和 OpenFeign 都对 Ribbon 进行了集成,都利用 Ribbon 维护了可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。
Feign 和 OpenFeign 都是在服务消费者(客户端)定义服务绑定接口并通过注解的方式进行配置,以实现远程服务的调用。
官方已经宣布停止更新Feign组件,所以可以使用OpenFeign进行代替
Feign | OpenFeign |
---|---|
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务,Feign的使用方式是:使用Feign的注解定义接口,调用这个接口就可以调用服务注册中心的服务 | OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。 OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务 |
Feign本身不支持SpringMVC的注解,它有一套自己的注解;
调用方式是通过@RequestLine指定HTTP协议及URL地址
OpenFeign客户端的默认超时时间为1秒钟,如果服务端处理请求的时间超过1秒就会报错(在一秒内不能请求到结果就会返回请求超时的错误)。可以通过在yml中假如以下内容进行配置
ribbon:
ReadTimeout: 6000 #建立连接所用的时间,适用于网络状况正常的情况下,两端两端连接所用的时间
ConnectionTimeout: 6000 #建立连接后,服务器读取到可用资源的时间
feign:
client:
httpclient:
enabled: true # 开启 HttpClient优化连接池
compression:
request:
enabled: true # 开启请求数据的压缩功能
mime-types: text/xml,application/xml, application/json # 压缩类型
min-request-size: 1024 # 最小压缩值标准,当数据大于 1024 才会进行压缩
response:
enabled: true # 开启响应数据压缩功能
yml添加日志级别声明
logging:
level:
com.xxx.xxx.xxxService:debug #feign日志以什么样的级别监控该接口
com.xxx.xxx.xxxService是开启@FeignClient注解的接口(即服务绑定接口)的完整类名。也可以只配置部分路径,表示监控该路径下的所有服务绑定接口
debug表示监听该接口的日志级别
//创建日志配置类
@Configuration
public class ConfigBean {
/**
* OpenFeign 日志增强
* 配置 OpenFeign 记录哪些内容
*/
@Bean
Logger.Level feginLoggerLevel() {
return Logger.Level.FULL;
}
}
这个配置的作用是通过配置的logger.level对象告诉OpenFeign记录哪些日志内容。logger.level的具体级别如下:
NONE:不记录任何信息。
BASIC:仅记录请求方法、URL以及响应状态码和执行时间。
HEADERS:除了记录BASIC级别的信息外,还会记录请求和响应的头信息。
FULL:记录所有请求与响应的明细,包括头信息,请求体,元数据等等。
FULL级别如图:
OpenFeign本质就是通过接口+注解实现对服务提供者的绑定,从而轻松实现服务之间的调用。OpenFeign的功能比较齐全;编写接口将远程调用的同一个微服务的API集中,可以很方便的管理API;
RestTemplate是从Spring3.0开始支持的一个HTTP请求工具,他提供了常见的REST请求方案的模板,例如GET请求、POST请求、PUT请求、DELETE请求以及一些通用的请求执行方法exchange以及execute。RestTemplate继承自InterceptingHttpAccessor并且实现了RespOperations接口,其中RestOperations接口定义了基本的RESTful操作,这些操作在RestTemplate中都得到了实现。
在RestTemplate中GET请求有这几个方法:
这些请求中有两类方法,分别是getForObject和getForEntity,每一个类都有三个重载方法。
getForEntity(String url, Class
除了这一种方法外,还有两种方法也就是getForEntity的两位两个重载方法,使用map
Map map = new HashMap<>();
map.put("name",name);
ResponseEntity responseEntity = restTemplate.getForEntity(url, String.class, map);
还有一种就是使用url对象
String url = "http://" + host + ":" + port + "/hello?name=" + URLEncoder.encode(name, "UTF-8");
URI uri = URI.create(url);
ResponseEntity responseEntity = restTemplate.getForEntity(uri,String.class);
注意这里使用URL如果是带了中文字符串,那么就需要使用UTF-8
getForObject 方法和 getForEntity 方法类似,getForObject 方法也有三个重载的方法,参数和 getForEntity 一样。
getForObject 和 getForEntity 的差异主要体现在返回值的差异上, getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。
例如,还是上面的请求,利用 getForObject 来发送 HTTP 请求,结果如下:
String url = "http://" + host + ":" + port + "/hello?name=" + URLEncoder.encode(name, "UTF-8");
URI uri = URI.create(url);
String s = restTemplate.getForObject(uri, String.class);
注意,这里返回的 s 就是 provider 的返回值,如果开发者只关心 provider 的返回值,并不关系 HTTP 请求的响应头,那么可以使用该方法。
在RestTemplate中POST请求有这几个方法:
post 请求的方法类型除了 postForEntity 和 postForObject 之外,还有一个 postForLocation。这里的方法类型虽然有三种,但是这三种方法重载的参数基本是一样的。
在Post请求中,参数的传递可以是key/value的形式,也可以是JSON数据、
postForObject和postforEntity基本一致,就是返回类型不同、
postForLocation方法的返回值是一个Url对象,因为POST请求一般用来添加数据,有的时候需要将刚刚添加成功的数据的url返回来,此时就可以使用这个方法,
注意:postForLocation方法返回的Url实际上是响应头的location字段,所以,provider中register接口的响应头必须要有location字段(即请求的接口是一个重定向的接口),否则PSOTForLocation方法的返回值就为null。
put请求的方法有三个
这三个重载的方法的参数和POST是一样对的,可以用key/value的形式传参,也可以用json的形式传参,无论哪种方式,都是没有返回值的。
delete请求方法有三个
不同于POST和PUT ,DELETE请求的参数只能在地址栏传送,可以是直接放在路径中,也可以用 key/value 的形式传递,当然,这里也是没有返回值的。
在RestTemplate中还有一个通用的方法exchange。为什么说它通用呢?因为这个方法需要你在调用的时候去指定请求类型,即它既能做GET请求,也能做POST请求,也能做其它各种类型的请求。如果需要对请求进行封装,使用它再合适不过了。
RestTemplate这个调用方式存在以下问题:
代码可读性差,编码体验不统一
参数负责URL难以维护
同一个服务提供者的名称可能分布在不同的controller里,或者一个controller中有几个不同的微服务提供者,这会比较难去管理。
请求方式不一样
RestTemplate需要每个请求都拼接url+参数+类文件,灵活性高但是消息封装臃肿。
feign可以伪装成类似SpringMVC的controller一样,将rest的请求进行隐藏,不用再自己拼接url和参数,可以便捷优雅地调用HTTP API。
底层实现方式不一样
RestTemplate在拼接url的时候,可以直接指定ip地址+端口号,不需要经过服务注册中心就可以直接请求接口;也可以指定服务名,请求先到服务注册中心(如nacos)获取对应服务的ip地址+端口号,然后经过HTTP转发请求到对应的服务接口(注意:这时候的restTemplate需要添加@LoadBalanced注解,进行负载均衡)。
Feign的底层实现是动态代理,如果对某个接口进行了@FeignClient注解的声明,Feign就会针对这个接口创建一个动态代理的对象,在调用这个接口的时候,其实就是调用这个接口的代理对象,代理对象根据@FeignClient注解中name的值在服务注册中心找到对应的服务,然后再根据@RequestMapping等其他注解的映射路径构造出请求的地址,针对这个地址,再从本地实现HTTP的远程调用。
本文是自己学习记录文章,可能有多处资料,如有侵权,请告知删除,也会更新一些关于本技术的新学习内容
转载地址:Feign与OpenFeign · 语雀 远程调用方式 RPC 和 Http