SpringCloud OpenFeign
目录
- 1.Openfeign 简介
- 2.Openfeign 的请求参数处理
- 3.Openfeign 的性能优化
- 4.配置 Openfeign 负载均衡请求超时时间
- 5 日志记录
1.Openfeign 简介
openFeign是对ribbon做了进一步的封装,OpenFeign是Spring Cloud 在Feign的基础上支持了Spring
MVC的注解,如@RequesMapping等等。通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
Openfeign 是一种声明式、模板化的 HTTP 客户端(仅在 Application Client 中使用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程 http 请求。
Spring Cloud 的声明式调用, 可以做到使用 HTTP 请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。
Openfeign 的应用,让 Spring Cloud 微服务调用像 Dubbo 一样,Application Client 直接通过接口方法远程调用 Application Service,而不需要通过常规的 RestTemplate 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。
1.1 使用 Feign 技术开发时的应用部署结构
在使用 Openfeign 技术开发 Spring Cloud 微服务时,需要先抽取要注册发布的服务标准,将这套标准通过接口的形式定义出来
在 Application Service 端开发中,依赖抽取的服务标准接口工程,并对接口给予实现
予实现。 在 Application Client 端开发中,依赖抽取的服务标准接口工程,并应用接口信息和 Openfeign 技术,实现远程服务的调用
在整体微服务开发中,Eureka Server 作为注册中心必不可少,注册中心的作用不变,仍旧是注册和发现服务
2.Openfeign 的请求参数处理
2.1 创建 Eureka Client 工程
2.1.1 POM 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>serviceapi</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<groupId>com.dqcgm</groupId>
<artifactId>cloud</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2.2 创建 Service API 服务标准 Module
2.3 开发服务标准 - Service API
2.3.1 POM 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.dqcgm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>serviceapi</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2.3.2 测试自定义参数类型
package com.dqcgm.entity;
import java.io.Serializable;
import java.util.Objects;
public class User implements Serializable {
private Integer id;
private String username;
private String remark;
public User(){}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) && Objects.equals(username, user.username) && Objects.equals(remark, user.remark);
}
@Override
public int hashCode() {
return Objects.hash(id, username, remark);
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}
2.3.3 服务接口定义
package com.dqcgm.serviceapi;
import com.dqcgm.entity.User;
import org.springframework.web.bind.annotation.*;
import java.util.List;
public interface FirstServiceAPI {
//测试 GET 请求的方法
//请求不传递任何的参数
@RequestMapping(value="/test", method= RequestMethod.GET)
public List<String> testFeign();
//测试 GET 请求传递一个普通的参数。 /get?id=xxx&name=yyy
//在为 Feign 定义服务标准接口的时候,处理请求参数的方法参数,必须使用 @RequestParam 注解描述
//且,无论方法参数名和请求参数名是否一致,都需要定义@RequestParam 注解的 value/name 属性。
@GetMapping(value="/get")
public User getMultiParams(@RequestParam(value = "id") Integer id, @RequestParam("name") String name);
//测试使用 POST 请求传递普通参数
//如果使用 POST 方式发起请求,传递多个普通参数,是使用请求头传递的参数。可以使用@RequestParam 注解来处理请求参数
@PostMapping(value="/post")
public User postMultiParams(@RequestParam(value = "id") Integer id, @RequestParam("name") String name);
//使用 POST 请求传递自定义类参数
//必须使用@RequestBody 处理。
@PostMapping(value="/postObjectParam")
public User postObjectParam(@RequestBody User pojo);
}
2.4 创建 Application Service 服务提供者 Module
2.5 开发服务提供者 - Application Service
2.5.1 POM 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.dqcgm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>openfeignservice</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.dqcgm</groupId>
<artifactId>serviceapi</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2.5.2 服务标准实现
package com.dqcgm.controller;
import com.dqcgm.entity.User;
import com.dqcgm.serviceapi.FirstServiceAPI;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
//对外提供服务的 Application Service。
//不能随便的定义服务。如果想让 Application Client 可以通过 Openfeign 技术访问当前类型提供的服务
//则必须遵循服务标准 - Service API
@RestController
public class OpenfeignServiceController implements FirstServiceAPI {
@Override
public List<String> testFeign() {
return Arrays.asList("测试 Openfeign", "此为返回结果");
}
@Override
public User getMultiParams(Integer id, String name) {
System.out.println("getMultiParams method run, parameters is [ id : " + id + " ; name : " + name + " ]");
User user = new User();
user.setId(id);
user.setUsername(name);
return user;
}
@Override
public User postMultiParams(Integer id, String name) {
System.out.println("postMultiParams method run, parameters is [ id : " + id + " ; name : " + name + " ]");
User user = new User();
user.setId(id);
user.setUsername(name);
return user;
}
@Override
public User postObjectParam(User pojo) {
System.out.println("postObjectParam method run, parameters is [ " + pojo + " ]");
return pojo;
}
}
2.5.3 配置文件 application.yml
server:
port: 8081
spring:
application:
name: openfeign-service
eureka:
client:
service-url:
- http://localhost:8761/eureka/
2.5.4 启动类
package com.dqcgm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OpenfeignServiceApp {
public static void main(String[] args) {
SpringApplication.run(OpenfeignServiceApp.class, args);
}
}
2.6 创建 Application Client 服务消费者 Module
2.7 开发服务消费者 - Application Client
2.7.1 POM 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.dqcgm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>openfeignclient</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.dqcgm</groupId>
<artifactId>serviceapi</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
2.7.2 本地服务接口
本地接口,继承服务标准接口 在接口上增加注解@FeignClient,代表当前接口是一个 Openfeign 技术中的服务消费端属性
name|value - 代表当前的 FeignClient 在请求 application service的时候,是访问哪一个服务所谓的哪一个服务,就是 application service 全局配置文件中的 spring.application.name 属性值
package com.dqcgm.service;
import com.dqcgm.serviceapi.FirstServiceAPI;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient("openfeign-service")
public interface FirstClientService extends FirstServiceAPI {}
2.7.3 控制器开发
package com.dqcgm.controller;
import com.dqcgm.entity.User;
import com.dqcgm.service.FirstClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class FirstClientController {
@Autowired
private FirstClientService firstClientService;
@GetMapping(value="/test")
public List<String> testFeign() {
return this.firstClientService.testFeign();
}
@GetMapping(value="/get")
public User getMultiParams(Integer id, String name) {
return this.firstClientService.getMultiParams(id, name);
}
@GetMapping(value="/post")
public User postMultiParams(Integer id, String name) {
return this.firstClientService.postMultiParams(id, name);
}
@GetMapping(value="/postObjectParam")
public User postObjectParam(User pojo) {
return this.firstClientService.postObjectParam(pojo);
}
}
2.7.4 配置文件 application.yml
server:
port: 8082
spring:
application:
name: openfeign-client
eureka:
client:
service-url:
- http://localhost:8761/eureka/
2.7.5 启动类
package com.dqcgm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
//@EnableFeignClients - 描述当前应用是一个使用 Openfeign 技术开发的服务消费端。
//属性 backPackage - 扫描的包,即使用@FeignClient 描述的接口所在包。此属性可省略,默认扫描当前工程所有包
@SpringBootApplication
@EnableFeignClients(basePackages = "com.dqcgm.service")
public class OpenfeignClientApp {
public static void main(String[] args) {
SpringApplication.run(OpenfeignClientApp.class, args);
}
}
2.8 参数处理简单总结
- 在 Openfeign 处理远程服务调用时,传递参数是通过 HTTP 协议传递的,参数存在的位置是请求头或请求体中。请求头传递的参数必须依赖@RequestParam 注解来处理请求参数,请求体传递的参数必须依赖@RequestBody 注解来处理请求参数
3.Openfeign 的性能优化
3.1 GZIP 简介
- gzip 介绍:gzip 是一种数据格式,采用用 deflate 算法压缩数据;gzip 是一种流行的数据压缩算法,应用十分广泛,尤其是在 Linux 平台
- gzip 能力:当 Gzip 压缩到一个纯文本数据时,效果是非常明显的,大约可以减少 70% 以上的数据大小。
- gzip 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取更快地检索网页。
3.2 HTTP 协议中的压缩传输简介
- 第一:客户端向服务器请求头中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示,客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务器是不会压缩的。
- 第二:服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消息头,表示响应报文是根据该格式压缩过的。
- 第三:客户端接收到响应之后,先判断是否有 Content-Encoding 消息头,如果有,按该格式解压报文。否则按正常报文处理。
3.3 在 Openfeign 技术中应用 GZIP 压缩
- 在 Spring Cloud 微服务体系中,一次请求的完整流程如下:
- 在整体流程中,如果使用 GZIP 压缩来传输数据,涉及到两次请求-应答。而这两次请求-应答的连接点是 Application Client,那么我们需要在 Application Client 中配置开启 GZIP 压缩,来实现压缩数据传输
3.3.1 只配置 Openfeign 请求-应答中的 GZIP 压缩
- 只开启 Feign 请求-应答过程中的 GZIP,也就是浏览器-Application Client 之间的请求应答不开启 GZIP 压缩
- 在全局配置文件中,使用下述配置来实现 Openfeign 请求-应答的 GZIP 压缩
server:
port: 8082
spring:
application:
name: openfeign-client
eureka:
client:
service-url:
- http://localhost:8761/eureka/
feign:
compression:
request:
# 开启请求 GZIP
enabled: true
# 设置支持 GZIP 压缩的 MIME 类型,即请求/响应类型。
mime-types:
csdn - application/xml
- application/json
# 配置启动压缩数据的最小阀值,单位字节。默认为 2048
min-request-size: 512
# 开启响应 GZIP
response:
enabled: true
3.3.2 配置全局 GZIP 压缩
- 在全局配置文件中配置下述内容,来开启所有请求-应答中的 GZIP 压缩,这里使用的是 Spring Boot 中的 GZIP 技术。
- 在 Spring Boot 中已经集成了 GZIP 压缩技术,并对所有的请求-应答实现 GZIP 数据压缩。工程中已经依赖了 Spring Boot 技术,所以在配置文件中可以开启 Spring Boot 中的 GZIP 压缩技术,对完整流程中所有相关的请求-应答开启 GZIP 压缩。
server:
port: 8082
compression:
# 开启 GZIP
enabled: true
# 设置支持 GZIP 压缩的 MIME 类型,即请求/响应类型
mime-types:
- application/json
- application/xml
- text/html
csdn - text/plain
# 配置启动压缩数据的最小阀值,单位字节。默认为 2048
min-response-size: 512
spring:
application:
name: openfeign-client
eureka:
client:
service-url:
- http://localhost:8761/eureka/
feign:
compression:
request:
# 开启请求 GZIP
enabled: true
# 设置支持 GZIP 压缩的 MIME 类型,即请求/响应类型
mime-types:
csdn - application/xml
- application/json
# 配置启动压缩数据的最小阀值,单位字节。默认为 2048
min-request-size: 512
# 开启响应 GZIP
response:
enabled: true
4.配置 Openfeign 负载均衡请求超时时间
- Openfeign 技术底层是通过 Ribbon 技术实现的,那么在负载均衡和超时时间配置上,主要对 Ribbon 的配置。具体配置如下:
4.1 超时时间配置
ribbon:
# 请求连接的超时时间,单位毫秒,默认的时间为 1 秒
ConnectTimeout: 1000
# 请求处理的超时时间,单位毫秒,默认的时间为 1 秒
ReadTimeout: 1000
4.2 负载均衡配置
# 设置负载均衡策略。openfeign-service 为设置负载均衡的服务名称
openfeign-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
5 日志记录
• Feign 只能记录 debug 级别的日志信息。
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.itheima: debug
• 定义Feign日志级别Bean
FeignLogConfig
package com.itheima.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfig {
/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
• 启用该Bean:
GoodsFeignClient
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)