往期回顾
前面我们已经介绍了Nacos
的安装与配置,Spring Cloud
集成Nacos
作为服务的注册中心和配置中心,集成Nacos
实现服务的负载均衡和一些常见的负载均衡策略以及使用Dubbo进行RPC调用
接下来,将介绍如何使用OpenFeign
进行RPC调用
关于RPC的一些相关概念前面的文章已经介绍过,这里不再赘述。如果还有疑问的同学可以参见
OpenFeign介绍
Spring Cloud OpenFeign 是声明式的服务调用工具,它整合了Ribbon
和Hystrix
,拥有负载均衡和服务容错功能
Feign
是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate
来调用服务接口的开发量。Feign
具备可插拔的注解支持,同时支持Feign
注解、JAX-RS注解及SpringMvc注解。当使用Feign时,Spring Cloud集成了Ribbon
和Eureka
以提供负载均衡的服务调用及基于Hystrix
的服务容错保护功能。
大家经常听到有人说OpenFeign,有人说Feign,给人一种好像是两个东西的错觉。其实是因为Feign本身也是Netflix的开源项目,后面独立出来单独做了开源项目,改名为OpenFeign。这种情况其实很常见,比如鸿蒙-HarmonyOS就有Open HarmonyOS。
快速开始
引入依赖
我们先在原有的项目工程上创建一个新的消费者模块
引入对应依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<!-- 将ribbon排除 -->
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加loadbalancer依赖
由于 Netflix Ribbon 进入停更维护阶段,因此 SpringCloud 2020.0.1 版本之后 删除了eureka中的ribbon,
替代ribbon的是spring cloud自带的LoadBalancer,默认使用的是轮询的方式
新版本的 Nacos discovery 都已经移除了 Ribbon ,此时我们需要引入 loadbalancer 代替,才能调用服务提供者提供的服务
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
添加相关配置
Nacos配置
新建bootstrap.yml
spring:
application:
name: user-openfeign-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.199.128:8848 #Nacos地址
config:
server-addr: 192.168.199.128:8848 #Nacos地址
file-extension: yaml #这里我们获取的yaml格式的配置
添加application.yml
server:
port: 7002
spring:
profiles:
active: dev
配置OpenFeign
日志级别
日志的级别分为四种:
NONE
:不记录任何日志信息,这是默认值。BASIC
:仅记录请求的方法,URL以及响应状态码和执行时间HEADERS
:在BASIC的基础上,额外记录了请求和响应的头信息FULL
:记录所有请求和响应的明细,包括头信息、请求体、元数据
日志的级别如果没有特殊要求,一般使用 NONE、BASIC 两个就好了,默认是NONE
注意:因为feign调试日志是debug级别输出,springboot默认的日志级别是info,所以feign的debug日志级别就不会输出,所以需要对Feign接口单独配置日志输出级别
# 因为feign调试日志是debug级别输出,springboot默认的日志级别是info,所以feign的debug日志级别就不会输出
# logging.level=debug这样配置是对所有的日志级别进行配置
# 该场景只需要对feign接口进行debug配置,所以是这样配置logging.level.com.example.order.feign=debug
logging:
level:
cuit.epoch.pymjl.service.UserFeignClient: debug
- Java代码的方式
可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level
的对象
先创建一个配置类
package cuit.epoch.pymjl.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
/**
* 在启动类的注解@EnableFeignClients上指定
* 局部生效就在@FeignClient中指定,不能加@Configuration注解
*
* @author Pymjl
* @version 1.0
* @date 2022/9/1 13:17
**/
public class OpenFeignConfig {
@Bean
public Logger.Level feignLogLevel() {
// 日志级别为BASIC
return Logger.Level.FULL;
}
}
如果要全局生效,将其放到 启动类的@EnableFeignClients
这个注解中
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = OpenFeignConfig.class)
public class OpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(OpenFeignApplication.class, args);
}
}
如果是局部生效,则把它放到对应的@FeignClient
这个注解中
@FeignClient(value = "user-service",configuration = OpenFeignConfig.class)
- 配置文件的方式
# 针对某个微服务的配置 userservice:微服务名称 FULL:日志级别
feign.client.config.userservice.logger-level=FULL
# 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
#feign.client.config.default.logger-level=FULL
配置LoadBalancer
- 配置负载均衡策略
/**
* 注意不要加@Configuration
*
* @author Pymjl
* @version 1.0
* @date 2022/8/26 13:05
**/
public class MyLoadBalancerConfig {
@Resource
NacosDiscoveryProperties nacosDiscoveryProperties;
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
// Nacos权重轮询
return new NacosLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class), name, nacosDiscoveryProperties);
}
}
- 配置
RestTemplate
/**
* 在这里配置我们自定义的LoadBalancer策略 如果想自己扩展算法 需要实现ReactorServiceInstanceLoadBalancer接口
* @LoadBalancerClients(defaultConfiguration = {name = "CLOUD-PAYMENT-SERVICE", configuration = MyLoadBalancerConfig.class})
* 注意这里的name属性 需要和Nacos页面中的服务提供者名字一致
*
* @author Pymjl
* @version 1.0
* @date 2022/8/26 12:20
**/
@Configuration
@LoadBalancerClient(name = "user-service", configuration = MyLoadBalancerConfig.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
超时配置
我们在通过 Feign 去调用接口,难免会遇到超时的问题,我们可以在 yml 文件设置超时属性,防止系统抛出超时异常
feign:
client:
config:
# 全局配置(default 默认就是适用于全部微服务)
default:
connectTimeout: 100000
readTimeout: 100000
# 单独配置
user-service:
connectTimeout: 300000
readTimeout: 300000
OpenFeign的其他配置
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可
常用的配置如下:
feign:
hystrix:
enabled: true #在Feign中开启Hystrix
compression:
request:
enabled: false #是否对请求进行GZIP压缩
mime-types: text/xml,application/xml,application/json #指定压缩的请求数据类型
min-request-size: 2048 #超过该大小的请求会被压缩
response:
enabled: false #是否对响应进行GZIP压缩
logging:
level: #修改日志级别
com.macro.cloud.service.UserService: debug
OpenFeign的优化
默认情况下,Feign 使用的是 UrlConnetcion
去请求,这种原生的请求方式一旦遇到高并发的情况下,响应会变得很慢,所以我们可以考虑加入连接池技术来优化性能, 比如常用的Ok Http
、Apache Http Client
在HTTP 通信的过程中,建立连接是一个很复杂的过程,涉及到多个数据包的交换,很耗时间,而且HTTP连接需要3次握手和4次挥手开销都很大。
这时可以采用HTTP连接池,节约大量的3次握手4次挥手时间,提升吞吐量。
默认的HttpURLConnection是JDK自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。
HttpClient 相比传统JDK自带的HttpURLConnection,它封装了访问HTTP的请求头,参数,内容体,响应等等。它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口(基于HTTP协议的),既提高了开发的效率,又提高了代码的健壮性。另外高并发大量的请求网络的时候,也是用"连接池"提升吞吐量。
OkHttp作为后期之秀,功能和性能上,可能稍优于HttpClient ,但是几乎没多大区别,实际使用时,都是可以的,不过HttpClient集成起来更方便
下面介绍下如何集成 Apache 下的 HttpClient 的连接池
- 先引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 编写对应的yml文件
feign:
httpclient:
enabled: true
max-connections: 200
max-connections-per-route: 50
编写对应的接口
- 先在服务提供者正常的编写
service
代码,然后将service
注入进controller
完成controller
的编写
/**
* @author Pymjl
* @version 1.0
* @date 2022/8/25 12:48
**/
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
UserService userService;
@GetMapping("/register")
public CommonResult<String> register() {
userService.register();
return ResultUtils.success();
}
@GetMapping("/get/{id}")
public CommonResult<User> get(@PathVariable("id") Long id) {
return ResultUtils.success(userService.get(id));
}
}
- 在消费者端编写对应的
FeignClient
,和我们平常的service接口没太大的区别,只是在上面加上对应的SpringMVC注解
/**
* @author Pymjl
* @version 1.0
* @date 2022/9/1 0:03
**/
@FeignClient(value = "user-service")
public interface UserFeignClient {
/**
* 注册
*
* @return {@code CommonResult<String>}
*/
@GetMapping("/user/register")
CommonResult<String> register();
/**
* 得到
*
* @param id id
* @return {@code CommonResult<User>}
*/
@GetMapping("/user/get/{id}")
CommonResult<User> get(@PathVariable("id") Long id);
}
注意value
的值要和nacos
中的服务提供者的名字相同
然后编写对应的消费者controller
/**
* @author Pymjl
* @version 1.0
* @date 2022/9/1 0:09
**/
@RestController
@RequestMapping("/consumer")
public class TestController {
@Resource
UserFeignClient userFeignClient;
@GetMapping("/register")
public CommonResult<String> register() {
return userFeignClient.register();
}
@GetMapping("/get/{id}")
public CommonResult<User> get(@PathVariable Long id) {
return userFeignClient.get(id);
}
}
测试
- 先启动服务提供者user-service,再启动消费者
- 访问对应接口
- 查看消费者后台日志输出
从上面可以看见,因为我们对OpenFegin
配置了日志的输出级别,控制台在访问对应的请求时打印了对应的HTTP接口的详情
- 查看提供者的日志输出
至此,整合Nacos
和 OpenFegin
就完成了,至于OpenFegin
整合Hystrix
进行服务的降级与熔断这里不做赘述,后面考虑整合Sentinel
Spring Cloud 之前使用的断路器是 Netfilx 开源的 Hystrix 。被很多开发人员作为默认的断路器来使用。2018 年 11 月,当 Netflix 宣布将这个项目置于维护模式时(不再开发新特性,只进行例行维护),Spring Cloud 官方也不得不跟进了 Netfix ,在 SpringOne 2019中,Spring 宣布将从 Spring Cloud 3.1 版本中删除 Hystrix 仪表板。要不了多长时间 Spring Cloud Netfix 将结束生命周期。
应的请求时打印了对应的HTTP接口的详情
- 查看提供者的日志输出
[外链图片转存中…(img-J4Qu3Fig-1662298670269)]
至此,整合Nacos
和 OpenFegin
就完成了,至于OpenFegin
整合Hystrix
进行服务的降级与熔断这里不做赘述,后面考虑整合Sentinel
Spring Cloud 之前使用的断路器是 Netfilx 开源的 Hystrix 。被很多开发人员作为默认的断路器来使用。2018 年 11 月,当 Netflix 宣布将这个项目置于维护模式时(不再开发新特性,只进行例行维护),Spring Cloud 官方也不得不跟进了 Netfix ,在 SpringOne 2019中,Spring 宣布将从 Spring Cloud 3.1 版本中删除 Hystrix 仪表板。要不了多长时间 Spring Cloud Netfix 将结束生命周期。