OpenFeign是Spring Cloud OpenFeign,是Spring Cloud团队开发的基于Feign的框架
1、OpenFeign功能升级
OpenFeign在Feign的基础上提供了以下增强和扩展功能
(1)便于集成Spring Cloud组件:OpenFeign与Spring Cloud其他组件(服务发现、负载均衡等)紧密集成
(2)支持@FeignClient注解:OpenFeign引入了@FeignClient注解作为Feign客户端的标识,可以方便地定义和使用远程服务的声明式接口
(3)错误处理改进:OpenFeign对异常处理增强,例如:OpenFeign提供错误编码器(DefaultErrorDecoder)和回退策略(当服务端返回错误响应或请求失败时,OpenFeign调用回退策略中的逻辑,提供一个默认的处理结果)
(4)更丰富的配置项:例如:超时设置、重试策略等
2、OpenFeign基本使用
OpenFeign通常要配合注册中心一起使用,并且新版本OpenFeign也必须和负载均衡器一起使用
(1)添加依赖(Nacos注册中心、OpenFeign、Spring Cloud LoadBalancer)
(2)配置Nacos服务信息
(3)在项目中开启OpenFeign
(4)编写OpenFeign调用代码
(5)编写代码通过OpenFeign调用生产者
代码的基本分块
2.1、添加依赖
总共添加三个依赖:Nacos注册中心、OpenFeign和LoadBalancer(在nacosr入门的时候,添加过这些依赖进行演示)
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2、配置Nacos服务端信息
以下采用yml格式的配置文件
2.2.1、消费者
spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false #表示注册显示 消费者 不需要显示
server:
port: 8080
2.2.2、提供者
spring:
application:
name: provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
server:
port: 9091
2.2.3、提供者业务代码
提供者访问路径 /user/getname 这里的路径的一会要提供给消费者的
@RestController
@RequestMapping("/user")
public class UserController {
//为了获取端口号 注入webServer相关注解
@Autowired
private WebServerApplicationContext serverApplicationContext;
@RequestMapping("/getname")
public String getName(@RequestParam("id") Integer id) throws InterruptedException {
Thread.sleep(1000);
System.out.println("------超时重试--------"+ LocalDateTime.now());
return "provider : "+id+" | port "+serverApplicationContext.getWebServer().getPort();
}
}
2.3、项目中开启OpenFeign
在消费者的Spring Boot启动类添加@EnableFeignClients注解
2.4、编写OpenFeign调用代码
消费者:接口的访问路径就是远程调用 这里路径是我们要访问提供者的路径,方法和提供者也是一样的,除了没有方法体
@Service
@FeignClient("provider") // 我们需要远程调用的服务, 也就是生产者名称 我们刚刚写的provider
public interface UserService {
@RequestMapping("/user/getname") //生产者的调用接口
public String getName(@RequestParam("id") Integer id);
}
2.5、调用OpenFeign接口代码
@RestController
public class UserController {
@Autowired // 注入我们远程调用的接口
private UserService userService;
@RequestMapping("/getname")
public String getName(Integer id){
return "consumer 调用 "+userService.getName(id);
}
}
3、超时重试机制
微服务之间是通过网络进行通信的,而网络是非常复制性和不稳定的,所以在调用服务可能失败或者超时,那么在这种情况,我们就需要给OpenFeign配置超时重试机制
超时重传:网络通信中一种策略,请求在一定时间内未能得到响应或得到超时响应的情况,当发起请求后,如果在规定的时间内没有得到预期响应,就会触发超时重试机制,重新发送请求
超时重试的主要目的是提高请求的可靠性和稳定性,以应对网络不稳定,服务不可用、响应延迟等不确定因素
OpenFeign默认情况下是不会自动开启超时重试的,所以想要开启超时重试,需要下面的步骤
(1)配置超时重传
(2)覆盖Retryer对象
3.1、配置超时重试
超时配置消费者访问的时候超时需要配置的,不是提供者
spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false #表示注册显示 消费者 不需要显示
openfeign: #OpenFeign配置超时重传配置
client:
config:
default: #全局配置
connect-timeout: 1000 #这里是ms单位 连接时间1s
read-timeout: 1000 # 读取超时时间 1s
server:
port: 8080
光配置是不行,这里需要从写一下Retryer
3.2、覆盖Retryer
在消费者(consumer)这个子模块中写config层,写一个Retryer注入到对象中
@Configuration
public class RetryerConfig {
@Bean
public Retryer retryer(){
//第一个参数 是 时间间隔 第二个参数 是最大超时时间 第三个参数是最大重试次数
return new Retryer.Default(
1000,
3000,
3
);
}
}
4、自定义超时重试机制
自定义超时重试机制的实现分为以下两步:
(1)自定义超时重试类(实现Retryer接口,并重写continueOrPropagate方法)
(2)设置配置文件
4.1、自定义超时重试类
常见超时重试策略有以下三种:
(1)固定间隔重试:每次重试之间的时间间隔固定不变,例如每次重试之间相隔1秒
(2)指数重试:每次重试之间的时间间隔按指数递增。例如,初始间隔为1秒,每次重试后加倍,第一次1s,第二次2s,第三次4s依次类推
(3)随机间隔重试:每次重试之间的时间间隔是随机的,通过引入随机性来防止多个失败请求同时发生,例如,每次重试的时间间隔在一定范围内随机选择
我们这里就写一个类继承Retryer 开始我们的自定义超时重试
我们这里同样是在config层写的
//重写不需要注入 直接会进行覆盖 实现 Retryer接口需要 重写continueOrPropagate和clone
//模仿这写就行
public class CustomRetryer implements Retryer {
private final int maxAttempts; //最大访问次数
private final long backoff; //重试间隔时间
private int attempt; //当前尝试次数
public CustomRetryer(){
this.maxAttempts=3;
this.backoff=1000;
this.attempt=0;
}
public CustomRetryer(int maxAttempts,long backoff){
this.maxAttempts=maxAttempts;
this.backoff=backoff;
this.attempt=0;
}
/*
* 失败重试方法
* */
@Override
public void continueOrPropagate(RetryableException e) {
if(attempt++>=maxAttempts){
throw e;
}
long interval=this.backoff;
System.out.println(LocalDateTime.now()+"| 执行一次重试");
try {
Thread.sleep(interval*attempt);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
/*
*克隆创建独立实例
* */
@Override
public Retryer clone() {
return new CustomRetryer(maxAttempts,backoff);
}
}
4.2、设置配置文件
只重写重试策略是不行的,还需要进行配置,让重试得时候跑我们自定义重试策略
spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
register-enabled: false #表示注册显示 消费者 不需要显示
openfeign: #OpenFeign配置超时重传配置
client:
config:
default: #全局配置
connect-timeout: 1000 #这里是ms单位 连接时间1s
read-timeout: 1000 # 读取超时时间 1s
retryer: com.example.consumer.config.CustomRetryer #添加路径
server:
port: 8080
运行结果:
这里的重试是有三次的,会打印四个超时重试,相差时间为2,3,4s,因为我们自定超时重试时间就是按照次数来计算时间的,第一次:间隔时间+1=2s 第二次:间隔时间+2=3s
也就是 间隔时间 + 第几次 = 超时时间
5、超时重试底层实现
“超时重试”基本就两个动作:“超时”和“重试”,对应底层实现也是不同的
5.1、超时底层实现
OpenFeign超时的底层实现是通过HTTP客户端来实现的
OpenFeign允许你在请求连接和读取数据阶段设置超时时间,具体的超时配置可以通过设置HTTP客户端连接超时(connectTimeout)和读取超时(readTimeout)来实现,你可以在配置文件中设置超时参数
OpenFeign底层的HTTP客户端,可以使用Apache HttpClient或OkHttpClient来实现,默认使用的是Apache HttpClient来实现的
5.2、重试底层实现
通过观察OpenFeign的源码实现就可以了解重试功能的底层实习,它的源码在就是invoke方法,如下所示:
底层实现基于RequestTemplate的
retryer实现continueOrPropagate方法
总结:OpenFeign的重试功能是通过其内置的Retryer组件和底层的HTTP客户端实现的,Retryer组件提供了重试策略的逻辑实现,而远程接口则通过HTTP客户端来完成调用