环境:Spring Boot3.2.5
1. 简介
OpenFeign 是一个声明式网络服务客户端,它让编写网络服务客户端变得更简单。使用 Feign 调用其他服务时,我们几乎不需要编写任何代码。我们只需创建一个接口并对其进行注解即可。它支持 OpenFeign 和 Jakarta JAX-RS 注释。
在篇文章,我们将深入 Spring Cloud OpenFeign 全方面的介绍各个知识点。
在介绍OpenFeign之前,我们先来对比下Feign vs. OpenFeign vs. Spring HttpExchange。
Feign、OpenFeign 和 Spring HttpExchange 都是用于在 Java 应用程序中创建声明式 HTTP 客户端。
| 功能 | Feign | OpenFeign | Spring HttpExchange |
|---|---|---|---|
| 起源与目的 | 由 Netflix 开发 | 扩展自Feign,功能大大增强 | Spring的一部分 |
| Spring集成 | 可用于 Spring 和非 Spring 应用程序 | 通过Spring Cloud OpenFeign 模块集成 | Spring特有 |
| 定制 | 可定制的组件、请求和响应 | 可定制的组件、请求和响应 | 更加细粒度的控制 |
| 社区 | 不太活跃 | 非常活跃 | 亲儿子,没得说 |
| 案例 | 微服务、RESTful API 集成 | 微服务、RESTful API 集成 | Spring应用程序中的自定义HTTP交互 |
在Spring Boot项目中,个人更建议使用HttpExchange,你无需引入任何其它的依赖。不过OpenFeign 与服务发现和负载平衡等其他 Spring Cloud组件集成得很好。而 HttpExchange 使用 WebClient 来调用 HTTP 请求,因此能更好地控制请求和响应处理。
但是,OpenFeign 是基于每请求线程模型的阻塞型客户端,对于每个请求,指定的线程都会阻塞,直到收到响应为止。HttpExchange 使用的 WebClient 是非阻塞和反应式的,因此很容易克服上述性能瓶颈。
OpenFeign不支持响应式的,如果你希望基于非阻塞,那么你可以查看下面这篇文章
深入ReactiveFeign:反应式远程接口调用的最佳实践
2. 实战案例
2.1 引入依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2022.0.3</version></dependency>
注意:根据你使用的Spring Boot版本引入对应Cloud版本。
2.2 开启功能
接下来,我们需要使用 @EnableFeignClients 注解启用 Feign Clients,该注解可对所有注释为 @FeignClient 的接口进行组件扫描。
public class AppApplication {}
这里配置了basePackages属性来指定要扫描的包,如果你的注解使用在启动类上,那么你可以不用指定。
2.3 声明Feign客户端
可以使用 @FeignClient 注解将接口声明为 Feign 客户端。下面创建一个简单的客户端,获取用户列表。
public interface UserFeignClient {ResponseEntity<List<User>> getUsers() ;}
说明:
value:指定客户端的名称。必填项,可以是任意值。
url:基本请求的URL。
在getUsers方法上使用了@GetMapping声明了具体的目标接口。
2.4 接口调用
要进行接口调用非常的简单,我们只需要在需要的地方注入上面的Feign接口即可。
private final UserFeignClient userFeignClient ;public UserFeignController (UserFeignClient userFeignClient) {this.userFeignClient = userFeignClient ;}// 接口处理ResponseEntity<List<User>> responseEntity = userFeignClient.getUsers() ;if (responseEntity.getStatusCode().is2xxSuccessful()) {List<User> usersList = responseEntity.getBody() ;usersList.forEach(System.out::println) ;} else if(responseEntity.getStatusCode().is4xxClientError()) {throw new BadRequestException("Bad Request") ;} else {throw new RuntimeException("Server Error") ;}
使用方法与普通的bean方式一样。
2.5 使用继承
为了避免模板代码,Feign 允许将常用功能归入基础接口。在下面的示例中,我们创建了一个新的 AccountFeignClient,它是从上面创建的 UserFeignClient 继承而来的。
public interface AccountFeignClient extends UserFeignClient {String getAccountByUser( Long id) ;}
注意:不支持多级继承。
2.6 OpenFeign配置
默认配置
每个 Feign 客户端都由一组组件组成,这些组件共同作用于远程服务调用。无论何时创建命名客户端,Spring Cloud 都会使用 FeignClientsConfiguration 为这些组件创建默认值。在该类中的大多数bean定义,我们都可以通过自定义的方式进行覆盖。
默认有:
Decoder:要对响应进行解码,需要使用封装了 SpringDecoder 的 ResponseEntityDecoder。
Encoder:SpringEncoder 用于对 RequestBody 进行编码。
Logger:Slf4jLogger 是 Feign 使用的默认日志记录器。
Contract:提供注解处理的 SpringMvcContract。
Feign.Builder:用于构建Feign组件。
Retryer:当容器中不存在断路器相关依赖或为开启时,可配置重试请求的策略。
Client:这是全局的,用来处理请求。
接下来,详细讲解自定义的配置。
自定义配置
Spring Cloud 允许我们通过指定附加配置,用来覆盖 FeignClientsConfiguration 中的默认bean配置。
如下,覆盖 AccountFeignClient 中的默认 HttpClient,使用 ApacheHttp5Client。我们需要创建一个配置类 AccountFeignConfiguration 并声明客户端 bean。
public class PackAccountFeignConfiguration {public CloseableHttpClient feignClient() {return HttpClients.createDefault() ;}}
接下来,可以在@FeignClient注解中如下定义
(value = "accountFeignClient",url = "http://localhost:8088/",configuration = PackAccountFeignConfiguration.class)public interface AccountFeignClient extends UserFeignClient {}
通过configuration属性指定我们自定义的配置。你还需要引入下面的依赖
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-hc5</artifactId></dependency>
如果你使用okhttp,那么也请引入对应的依赖即可。
通过配置文件配置
我们还可以使用应用程序属性覆盖配置。在这里,我们也可以为特定的 Feign 客户端或所有客户端重写配置。
如下,将所有的Feign客户端配置超时时间
spring:cloud:openfeign:config:default:connectTimeout: 5000
同样,如果我们只想覆盖 AccountFeignClient 的超时,可以使用使用 "value "属性指定的 Feign Client 名称进行如下设置。
spring:cloud:openfeign:config:accountFeignClient:connectTimeout: 5000
注意:如果我们同时创建 @Configuration Bean 和配置属性,属性值将优先于 @Configuration 值。我们可以通过设置 spring.cloud.openfeign.client.default-to-properties 来更改优先级。
spring:cloud:openfeign:client:: false
这样配置后,就不是属性值配置有限了。
拦截器配置
Feign 提供了 RequestInterceptor 接口,可用于执行身份验证或日志记录等任务。
RequestInterceptor requestInterceptor() {return requestTemplate -> {requestTemplate.header("requestID", "UUID");} ;}
为请求添加自定义的请求header。
异常处理
Feign 的默认 ErrorDecoder 会在出现错误时抛出 FeignException。我们可以编写自己的自定义 ErrorDecoder。这样,我们就可以进行特定的错误处理。
ErrorDecoder errorDecoder() {return new ErrorDecoder() {public Exception decode(String methodKey, Response response) {return switch (response.status()) {case 400 -> new BadRequestException(response) ;case 429 -> new TooManyRequestsException(response) ;default -> new Exception("feign client exception") ;} ;} ;}
在这里你可以更细粒度的根据状态来处理异常。
读写超时配置
Feign 允许我们配置连接和读取超时。可以为每个客户端或所有客户端进行配置。
spring:cloud:openfeign:client:config:default:: 5000: 5000
这将为所有的客户端配置同样的超时时间。
日志配置
默认情况下,每个 Feign 客户端都会创建一个日志记录器。要启用日志记录,我们需要在应用程序属性中使用客户端的软件包名称声明日志记录。
logging:level:com.pack.feign: DEBUG
这将该包中所有客户端的日志记录。如果我们只需要为特定客户端启用日志记录,可以通过在属性中明确指定客户端来实现。
logging:level:com.pack.feign.AccountFeignClient: DEBUG
Feign 提供了日志记录级别,以显示我们需要的客户端日志记录级别。让我们在配置类中添加一些基本日志。
@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
有4个等级:
NONE:无日志。
BASIC:记录请求方法和 URL 以及响应状态代码和执行时间。
HEADERS:除基本日志记录外,它还记录请求和响应标头。
FULL:记录请求和响应的标头、正文和元数据完整信息。
有关更多关于OpenFeign高级用法,请查看下面这篇文章
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
弃用Spring Cache!首选多级缓存框架JetCache
我给Spring提交一个Bug,已在最新版修复!请这样修复!
SpringBoot3必须掌握的5个强大功能,其中JVM优化技巧太厉害了
SpringBoot中Controller接口参数这样处理太优雅了
你的项目中是否运用了@ResponseStatus注解?你真的会用?



