声明式服务调用Feign
目录
1、背景
前文我们已经学到,当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。
2、Feign概述
Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。工作在consumer端。
Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。
ribbon + restTemplate 优化后 = feign
3、Fegin入门
3.1、创建工程
1、 拷贝ribbon_provider_1
2、application.yml
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.216.133:8848
application:
name: feign-provider
3.2、创建feign接口
1、创建工程
2、pom.xml
<dependencies>
<!--Spring Cloud OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.bjpowernode</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
3、feign
@FeignClient("feign-provider")
@RequestMapping("/provider")
public interface UserFeign {
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id);
}
3.3、创建服务消费者
1.创建工程
2、pom.xml
<!--feign接口-->
<dependency>
<groupId>com.zzcsy</groupId>
<artifactId>feign_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3、controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;//代理类
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
System.out.println(userFeign.getClass());
return userFeign.getUserById(id);
}
}
4、App
@SpringBootApplication
@EnableDiscoveryClient
//@EnableFeignClients(basePackages = "com.bjpowernode.feign")
@EnableFeignClients//开启feign接口扫描
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
4、feign原理
4.1、将Feign接口代理类注入到Spring容器中
@EnableFeignClients开启feign注解扫描,调用FeignClientsRegistrar.registerFeignClients()方法扫描@FeignClient注解的接口生成代理类,并把接口和代理类交给Spring的容器管理。
4.2、为接口的方法创建RequestTemplate
当consumer调用feign代理类时,代理类会调用SynchronousMethodHandler.invoke()创建RequestTemplate(url,参数)
4. 3、发起请求
代理类会通过RequestTemplate创建Request,然后client(URLConnetct、HttpClient、OkHttp)使用Request发送请求
5、feign参数传递
5.1传参方式:
-
restful风格:
@PathVarible
【拼接restful形式的url】
-
?传参
@RequestParam
【拼接?形式的url】
-
pojo参数
@RequestBody User user
【获取请求体中的json串】
6、feign优化
6.1、开启feign日志
feign:
client:
config:
default:
loggerLevel: full #开启feign全局日志
logging:
level:
com.zzcsy.feign: debug #开启单个项目的日志
6.2、fegin超时
6.2.1、方式一、
ribbon:
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 5000 #请求处理的超时时间
6.2.2、方式二、
feign:
client:
config:
feign-provider:
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 5000 #请求处理的超时时间
6.3、http连接池
两台服务器建立 http 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并且也很耗时间。 Http 连接需要的 3 次握手 4 次分手开销很大,这一开销对于大量的比较小的 http 消息来说更大。
优化解决方案
如果我们直接采用 http 连接池,节约了大量的 3 次握手 4 次分手;这样能大大提升吞
吐率。feign 的 http 客户端支持 3 种框架;HttpURLConnection、httpclient、okhttp;默认是
HttpURLConnection。
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
6.4、gzip压缩
6.4.1、gzip 介绍:
gzip 是一种数据格式,采用用 deflate 算法压缩 data;gzip 是一种流行的文件压缩算法,应用十分广泛,尤其是在 Linux 平台。
6.4.2、gzip 能力:
当 Gzip 压缩到一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小。
6.4.3、gzip 作用:
网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是Gzip与搜索引擎的抓取工具有着更好的关系。例如 Google就可以通过直接读取 gzip 文件来比普通手工抓取 更快地检索网页。
6.4.4、HTTP 协议中关于压缩传输的规定:
第一:客户端向服务器请求中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示,
客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务器是不会压缩的。
第二:服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支
持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消
息头,表示响应报文是根据该格式压缩过的。
第三:客户端接收到请求之后,先判断是否有 Content-Encoding 消息头,如果有,按该
格式解压报文。否则按正常报文处理。
6.4.5、配置gzip压缩:
server:
compression:
enabled: true #开启gzip压缩