跳到主要内容

Spring Cloud OpenFeign 特性

DeepSeek V3 中英对照 Spring Cloud OpenFeign Features

声明式 REST 客户端:Feign

Feign 是一个声明式的 Web 服务客户端。它使得编写 Web 服务客户端变得更加简单。要使用 Feign,只需创建一个接口并对其进行注解。它支持可插拔的注解,包括 Feign 注解和 JAX-RS 注解。Feign 还支持可插拔的编码器和解码器。Spring Cloud 增加了对 Spring MVC 注解的支持,并默认使用 Spring Web 中的 HttpMessageConverters。Spring Cloud 集成了 Eureka、Spring Cloud CircuitBreaker 以及 Spring Cloud LoadBalancer,以便在使用 Feign 时提供一个负载均衡的 HTTP 客户端。

如何包含 Feign

要在项目中包含 Feign,请使用 group 为 org.springframework.cloud 和 artifact id 为 spring-cloud-starter-openfeign 的 starter。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud 项目页面

示例 Spring Boot 应用

@SpringBootApplication
@EnableFeignClients
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}
java
@FeignClient("stores")
public interface StoreClient {
@RequestMapping(method = RequestMethod.GET, value = "/stores")
List<Store> getStores();

@GetMapping("/stores")
Page<Store> getStores(Pageable pageable);

@PostMapping(value = "/stores/{storeId}", consumes = "application/json",
params = "mode=upsert")
Store update(@PathVariable("storeId") Long storeId, Store store);

@DeleteMapping("/stores/{storeId:\\d+}")
void delete(@PathVariable Long storeId);
}
java

@FeignClient 注解中,String 类型的值(如上例中的 "stores")是一个任意的客户端名称,用于创建 Spring Cloud LoadBalancer 客户端。你也可以使用 url 属性指定一个 URL(绝对路径或仅主机名)。在应用上下文中,Bean 的名称是接口的全限定名。要指定自己的别名值,可以使用 @FeignClient 注解的 qualifiers 值。

上面的负载均衡客户端将希望发现 "stores" 服务的物理地址。如果你的应用程序是一个 Eureka 客户端,那么它将在 Eureka 服务注册中心解析该服务。如果你不想使用 Eureka,你可以使用 SimpleDiscoveryClient 在你的外部配置中配置一个服务器列表。

Spring Cloud OpenFeign 支持 Spring Cloud LoadBalancer 阻塞模式下的所有功能。你可以在 项目文档 中了解更多相关信息。

提示

要在带有 @Configuration 注解的类上使用 @EnableFeignClients 注解,请确保指定客户端的位置,例如:@EnableFeignClients(basePackages = "com.example.clients") 或显式列出它们:@EnableFeignClients(clients = InventoryServiceFeignClient.class)

为了在多模块设置中加载 Spring Feign 客户端 bean,你需要直接指定包。

注意

由于 FactoryBean 对象可能会在初始上下文刷新之前实例化,而 Spring Cloud OpenFeign Clients 的实例化会触发上下文刷新,因此它们不应在 FactoryBean 类中声明。

属性解析模式

在创建 Feign 客户端 bean 时,我们会解析通过 @FeignClient 注解传递的值。从 4.x 版本开始,这些值会被提前解析。对于大多数用例来说,这是一个很好的解决方案,同时也支持 AOT(Ahead-of-Time)编译。

如果你需要延迟解析属性,请将 spring.cloud.openfeign.lazy-attributes-resolution 属性的值设置为 true

提示

对于 Spring Cloud Contract 测试集成,应使用懒加载属性解析。

覆盖 Feign 默认设置

Spring Cloud 的 Feign 支持中的一个核心概念是命名客户端。每个 Feign 客户端都是一个组件集合的一部分,这些组件协同工作以按需联系远程服务器,而该集合有一个名称,作为应用程序开发者的你可以通过 @FeignClient 注解为其命名。Spring Cloud 使用 FeignClientsConfiguration 为每个命名的客户端按需创建一个新的集合作为 ApplicationContext。这个集合中包含了(除其他内容外)一个 feign.Decoder、一个 feign.Encoder 和一个 feign.Contract。你可以通过使用 @FeignClient 注解的 contextId 属性来覆盖该集合的名称。

Spring Cloud 允许你通过使用 @FeignClient 声明额外的配置(在 FeignClientsConfiguration 之上)来完全控制 Feign 客户端。示例:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
//..
}
java

在这种情况下,客户端由 FeignClientsConfiguration 中已有的组件以及 FooConfiguration 中的任何组件组成(后者将覆盖前者)。

备注

FooConfiguration 不需要使用 @Configuration 进行注解。然而,如果确实使用了 @Configuration 注解,那么请注意将其从任何 @ComponentScan 中排除,否则该配置将成为 feign.Decoderfeign.Encoderfeign.Contract 等的默认来源。可以通过将其放在与任何 @ComponentScan@SpringBootApplication 不重叠的单独包中来避免这种情况,或者可以在 @ComponentScan 中显式排除它。

备注

除了更改 ApplicationContext 集合的名称外,使用 @FeignClient 注解的 contextId 属性还会覆盖客户端名称的别名,并且它将作为为该客户端创建的配置 bean 名称的一部分。

注意

以前,使用 url 属性时,不需要 name 属性。现在必须使用 name

占位符在 nameurl 属性中受支持。

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
//..
}
java

Spring Cloud OpenFeign 默认提供以下用于 Feign 的 Bean(BeanType beanName: ClassName):

  • Decoder feignDecoder: ResponseEntityDecoder (包装了一个 SpringDecoder)

  • Encoder feignEncoder: SpringEncoder

  • Logger feignLogger: Slf4jLogger

  • MicrometerObservationCapability micrometerObservationCapability: 如果 feign-micrometer 在类路径上并且 ObservationRegistry 可用

  • MicrometerCapability micrometerCapability: 如果 feign-micrometer 在类路径上,MeterRegistry 可用并且 ObservationRegistry 不可用

  • CachingCapability cachingCapability: 如果使用了 @EnableCaching 注解。可以通过 spring.cloud.openfeign.cache.enabled 禁用。

  • Contract feignContract: SpringMvcContract

  • Feign.Builder feignBuilder: FeignCircuitBreaker.Builder

  • Client feignClient: 如果 Spring Cloud LoadBalancer 在类路径上,则使用 FeignBlockingLoadBalancerClient。如果两者都不在类路径上,则使用默认的 feign client。

备注

spring-cloud-starter-openfeign 支持 spring-cloud-starter-loadbalancer。然而,由于它是一个可选的依赖项,如果您想使用它,您需要确保它已添加到您的项目中。

要使用基于 OkHttpClient 的 Feign 客户端和 Http2Client Feign 客户端,请确保所需的客户端在类路径上,并分别将 spring.cloud.openfeign.okhttp.enabledspring.cloud.openfeign.http2client.enabled 设置为 true

对于基于 Apache HttpClient 5 的 Feign 客户端,只需确保 HttpClient 5 在类路径中即可,但你仍然可以通过将 spring.cloud.openfeign.httpclient.hc5.enabled 设置为 false 来禁用 Feign 客户端对它的使用。你可以通过提供一个 org.apache.hc.client5.http.impl.classic.CloseableHttpClient 类型的 bean 来自定义使用的 HTTP 客户端(当使用 Apache HC5 时)。

你可以通过在 spring.cloud.openfeign.httpclient.xxx 属性中设置值来进一步自定义 HTTP 客户端。以 httpclient 为前缀的属性适用于所有客户端,以 httpclient.hc5 为前缀的属性适用于 Apache HttpClient 5,以 httpclient.okhttp 为前缀的属性适用于 OkHttpClient,以 httpclient.http2 为前缀的属性适用于 Http2Client。你可以在附录中找到可以自定义的完整属性列表。如果无法通过属性配置 Apache HttpClient 5,可以使用 HttpClientBuilderCustomizer 接口进行编程式配置。

提示

从 Spring Cloud OpenFeign 4 开始,不再支持 Feign Apache HttpClient 4。我们建议改用 Apache HttpClient 5。

Spring Cloud OpenFeign 默认不 为 feign 提供以下 bean,但仍然会从应用程序上下文中查找这些类型的 bean 来创建 feign 客户端:

  • Logger.Level(日志级别)

  • Retryer(重试器)

  • ErrorDecoder(错误解码器)

  • Request.Options(请求选项)

  • Collection<RequestInterceptor>(请求拦截器集合)

  • SetterFactory(设置器工厂)

  • QueryMapEncoder(查询映射编码器)

  • Capability(默认提供 MicrometerObservationCapabilityCachingCapability 能力)

默认情况下会创建一个类型为 RetryerRetryer.NEVER_RETRY bean,这将禁用重试。请注意,这种重试行为与 Feign 的默认行为不同,Feign 默认会自动重试 IOExceptions,将它们视为与网络相关的临时异常,并且会重试从 ErrorDecoder 抛出的任何 RetryableException。

创建一个这些类型的 bean 并将其放置在 @FeignClient 配置中(例如上面的 FooConfiguration),可以让你覆盖每个描述的 bean。示例:

@Configuration
public class FooConfiguration {
@Bean
public Contract feignContract() {
return new feign.Contract.Default();
}

@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("user", "password");
}
}
java

这将 SpringMvcContract 替换为 feign.Contract.Default,并向 RequestInterceptor 集合中添加了一个 RequestInterceptor

@FeignClient 也可以通过配置属性进行配置。

application.yml
yaml
spring:
cloud:
openfeign:
client:
config:
feignName:
url: http://remote-service.com
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
defaultQueryParameters:
query: queryValue
defaultRequestHeaders:
header: headerValue
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
responseInterceptor: com.example.BazResponseInterceptor
dismiss404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
capabilities:
- com.example.FooCapability
- com.example.BarCapability
queryMapEncoder: com.example.SimpleQueryMapEncoder
micrometer.enabled: false
yaml

在这个示例中,feignName 指的是 @FeignClientvalue,它也被 @FeignClientname@FeignClientcontextId 所别名。在负载均衡的场景中,它还对应于将用于检索实例的服务端应用的 serviceId。指定的解码器、重试器和其他类的类必须在 Spring 上下文中有一个 bean 或者有一个默认的构造函数。

可以在 @EnableFeignClientsdefaultConfiguration 属性中指定默认配置,方式与上述类似。不同之处在于,此配置将应用于所有 Feign 客户端。

如果你更喜欢使用配置属性来配置所有的 @FeignClient,你可以创建一个带有 default Feign 名称的配置属性。

你可以使用 spring.cloud.openfeign.client.config.feignName.defaultQueryParametersspring.cloud.openfeign.client.config.feignName.defaultRequestHeaders 来指定将随名为 feignName 的客户端的每个请求一起发送的查询参数和请求头。

application.yml
yaml

这是一个 YAML 配置文件,通常用于 Spring Boot 应用程序中。YAML 是一种人类可读的数据序列化格式,常用于配置文件。application.yml 文件通常包含应用程序的配置属性,如数据库连接、服务器端口、日志级别等。

spring:
cloud:
openfeign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
yaml

如果我们同时创建了 @Configuration bean 和配置属性,配置属性将会优先。它会覆盖 @Configuration 的值。但如果你想将优先级改为 @Configuration,可以将 spring.cloud.openfeign.client.default-to-properties 设置为 false

如果我们想要创建多个具有相同名称或 URL 的 Feign 客户端,以便它们指向同一个服务器,但每个客户端都有不同的自定义配置,那么我们必须使用 @FeignClientcontextId 属性,以避免这些配置 bean 的名称冲突。

@FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class)
public interface FooClient {
//..
}
java
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
public interface BarClient {
//..
}
java

也可以配置 FeignClient 不从父上下文中继承 bean。你可以通过在 FeignClientConfigurer bean 中重写 inheritParentConfiguration() 方法并返回 false 来实现这一点:

@Configuration
public class CustomConfiguration {
@Bean
public FeignClientConfigurer feignClientConfigurer() {
return new FeignClientConfigurer() {
@Override
public boolean inheritParentConfiguration() {
return false;
}
};
}
}
java
提示

默认情况下,Feign 客户端不会对斜杠 / 字符进行编码。你可以通过将 spring.cloud.openfeign.client.decode-slash 的值设置为 false 来改变这一行为。

提示

默认情况下,Feign 客户端不会从请求路径中移除尾部斜杠 / 字符。你可以通过将 spring.cloud.openfeign.client.remove-trailing-slash 的值设置为 true 来改变这一行为。移除请求路径中的尾部斜杠将在下一个主要版本中成为默认行为。

SpringEncoder 配置

在我们提供的 SpringEncoder 中,我们为二进制内容类型设置了 null 字符集,而为所有其他类型设置了 UTF-8 字符集。

你可以通过将 spring.cloud.openfeign.encoder.charset-from-content-type 的值设置为 true 来修改此行为,从而从 Content-Type 头部的 charset 派生字符集。

超时处理

我们可以在默认客户端和命名客户端上配置超时。OpenFeign 使用两个超时参数:

  • connectTimeout 防止由于服务器处理时间过长而导致调用者阻塞。

  • readTimeout 从连接建立时开始应用,并在返回响应时间过长时触发。

备注

如果服务器未运行或不可用,数据包将导致 连接被拒绝。通信将以错误消息或回退结束。如果 connectTimeout 设置得非常低,这种情况可能会在超时 之前 发生。执行查找和接收此类数据包所需的时间是造成此延迟的主要原因。根据涉及 DNS 查找的远程主机,这一时间可能会发生变化。

手动创建 Feign 客户端

在某些情况下,可能需要以无法通过上述方法实现的方式自定义你的 Feign 客户端。在这种情况下,你可以使用 Feign Builder API 创建客户端。以下是一个示例,它创建了两个具有相同接口的 Feign 客户端,但为每个客户端配置了单独请求拦截器。

@Import(FeignClientsConfiguration.class)
class FooController {

private FooClient fooClient;

private FooClient adminClient;

@Autowired
public FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) {
this.fooClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.addCapability(micrometerObservationCapability)
.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
.target(FooClient.class, "https://PROD-SVC");

this.adminClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.addCapability(micrometerObservationCapability)
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(FooClient.class, "https://PROD-SVC");
}
}
java
备注

在上面的示例中,FeignClientsConfiguration.class 是 Spring Cloud OpenFeign 提供的默认配置。

备注

PROD-SVC 是客户端将要向其发出请求的服务名称。

备注

Feign 的 Contract 对象定义了接口上哪些注解和值是有效的。自动装配的 Contract bean 提供了对 SpringMVC 注解的支持,而不是默认的 Feign 原生注解。不建议将 Spring MVC 注解和原生 Feign 注解混合使用。

你也可以使用 Builder 来配置 FeignClient 不从父上下文中继承 bean。你可以通过在 Builder 上调用 inheritParentContext(false) 来实现这一点。

Feign Spring Cloud 断路器支持

如果 Spring Cloud CircuitBreaker 在类路径上且 spring.cloud.openfeign.circuitbreaker.enabled=true,Feign 将使用断路器包装所有方法。

要在每个客户端的基础上禁用 Spring Cloud CircuitBreaker 支持,可以使用 "prototype" 作用域创建一个普通的 Feign.Builder,例如:

@Configuration
public class FooConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
java

断路器的名称遵循以下模式:<feignClientClassName>#<calledMethod>(<parameterTypes>)。当调用一个带有 FooClient 接口的 @FeignClient,并且调用的接口方法 bar 没有参数时,断路器的名称将为 FooClient#bar()

备注

自 2020.0.2 版本起,断路器名称模式已从 <feignClientName>_<calledMethod> 更改。使用 2020.0.4 版本中引入的 CircuitBreakerNameResolver,断路器名称可以保留旧模式。

通过提供一个 CircuitBreakerNameResolver 的 Bean,你可以更改断路器名称的格式。

@Configuration
public class FooConfiguration {
@Bean
public CircuitBreakerNameResolver circuitBreakerNameResolver() {
return (String feignClientName, Target<?> target, Method method) -> feignClientName + "_" + method.getName();
}
}
java

要启用 Spring Cloud CircuitBreaker 分组功能,请将 spring.cloud.openfeign.circuitbreaker.group.enabled 属性设置为 true(默认值为 false)。

使用配置属性配置断路器

你可以通过配置属性来配置断路器(CircuitBreakers)。

例如,如果你有这样一个 Feign 客户端

@FeignClient(url = "http://localhost:8080")
public interface DemoClient {

@GetMapping("demo")
String getDemo();
}
java

你可以通过以下方式使用配置属性来进行配置

spring:
cloud:
openfeign:
circuitbreaker:
enabled: true
alphanumeric-ids:
enabled: true
resilience4j:
circuitbreaker:
instances:
DemoClientgetDemo:
minimumNumberOfCalls: 69
timelimiter:
instances:
DemoClientgetDemo:
timeoutDuration: 10s
yaml
备注

如果你想切换回 Spring Cloud 2022.0.0 之前使用的断路器名称,可以将 spring.cloud.openfeign.circuitbreaker.alphanumeric-ids.enabled 设置为 false

Feign Spring Cloud 断路器回退

Spring Cloud CircuitBreaker 支持回退(fallback)的概念:当断路器打开或发生错误时,会执行默认的代码路径。要为给定的 @FeignClient 启用回退功能,请将 fallback 属性设置为实现回退的类名。你还需要将你的实现声明为一个 Spring bean。

@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient {

@GetMapping("/hello")
Hello getHello();

@GetMapping("/hellonotfound")
String getException();

}

@Component
static class Fallback implements TestClient {

@Override
public Hello getHello() {
throw new NoFallbackAvailableException("Boom!", new RuntimeException());
}

@Override
public String getException() {
return "Fixed response";
}

}
java

如果需要在触发回退时访问导致回退的原因,可以在 @FeignClient 中使用 fallbackFactory 属性。

@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
fallbackFactory = TestFallbackFactory.class)
protected interface TestClientWithFactory {

@GetMapping("/hello")
Hello getHello();

@GetMapping("/hellonotfound")
String getException();

}

@Component
static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {

@Override
public FallbackWithFactory create(Throwable cause) {
return new FallbackWithFactory();
}

}

static class FallbackWithFactory implements TestClientWithFactory {

@Override
public Hello getHello() {
throw new NoFallbackAvailableException("Boom!", new RuntimeException());
}

@Override
public String getException() {
return "Fixed response";
}

}
java

Feign 和 @Primary

在使用 Feign 与 Spring Cloud CircuitBreaker 回退功能时,ApplicationContext 中会存在多个相同类型的 bean。这会导致 @Autowired 无法正常工作,因为没有唯一的一个 bean,或者没有被标记为主要的 bean。为了解决这个问题,Spring Cloud OpenFeign 将所有 Feign 实例标记为 @Primary,这样 Spring 框架就知道应该注入哪个 bean。在某些情况下,这可能不是期望的行为。要关闭此行为,可以将 @FeignClientprimary 属性设置为 false

@FeignClient(name = "hello", primary = false)
public interface HelloClient {
// methods here
}
java

Feign 继承支持

Feign 支持通过单继承接口来实现样板化的 API。这种方式允许将常见的操作分组到方便的基础接口中。

public interface UserService {

@GetMapping("/users/{id}")
User getUser(@PathVariable("id") long id);
}
java
@RestController
public class UserResource implements UserService {

}
java
@FeignClient("users")
public interface UserClient extends UserService {

}
java
注意

@FeignClient 接口不应在服务器和客户端之间共享,并且不再支持在类级别上使用 @RequestMapping 注解来标注 @FeignClient 接口。

Feign 请求/响应压缩

你可以考虑为你的 Feign 请求启用请求或响应的 GZIP 压缩。你可以通过启用以下属性之一来实现:

feign.compression.request.enabled: true
feign.compression.response.enabled: true
yaml

这些属性可以分别启用请求和响应的 GZIP 压缩。

spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true
java

Feign 请求压缩提供了类似于您可能为 Web 服务器设置的配置:

spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
spring.cloud.openfeign.compression.request.min-request-size=2048
java

这些属性允许您选择性地设置压缩的媒体类型和最小请求阈值长度。

当请求匹配 spring.cloud.openfeign.compression.request.mime-types 中设置的 MIME 类型以及 spring.cloud.openfeign.compression.request.min-request-size 中设置的大小时,spring.cloud.openfeign.compression.request.enabled=true 会导致将压缩头添加到请求中。这些头的功能是向服务器发出信号,表示客户端期望接收压缩的响应体。服务器端应用程序有责任根据客户端提供的头信息提供压缩的响应体。

提示

由于 OkHttpClient 使用“透明”压缩,如果存在 content-encodingaccept-encoding 头部,该压缩会被禁用。因此,当类路径中存在 feign.okhttp.OkHttpClient 并且 spring.cloud.openfeign.okhttp.enabled 设置为 true 时,我们不会启用压缩。

Feign 日志记录

为每个创建的 Feign 客户端都会创建一个日志记录器。默认情况下,日志记录器的名称是用于创建 Feign 客户端的接口的完整类名。Feign 日志记录仅响应 DEBUG 级别。

logging.level.project.user.UserClient: DEBUG
yaml

Logger.Level 对象可以针对每个客户端进行配置,它告诉 Feign 需要记录多少日志。可选项包括:

  • NONE,不记录日志(默认)。

  • BASIC,仅记录请求方法、URL、响应状态码和执行时间。

  • HEADERS,记录基本信息以及请求和响应头。

  • FULL,记录请求和响应的头、正文和元数据。

例如,以下代码会将 Logger.Level 设置为 FULL

@Configuration
public class FooConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
java

Feign 能力支持

Feign 功能暴露了核心的 Feign 组件,以便这些组件可以被修改。例如,该功能可以获取 Client,对其进行装饰,然后将装饰后的实例返回给 Feign。对 Micrometer 的支持就是一个很好的现实例子。请参阅 Micrometer 支持

创建一个或多个 Capability bean 并将其放置在 @FeignClient 配置中,可以让你注册它们并修改相关客户端的行为。

@Configuration
public class FooConfiguration {
@Bean
Capability customCapability() {
return new CustomCapability();
}
}
java

Micrometer 支持

如果以下所有条件都为真,将创建并注册一个 MicrometerObservationCapability bean,以便您的 Feign 客户端可以通过 Micrometer 进行观测:

  • feign-micrometer 在类路径上

  • 一个 ObservationRegistry bean 可用

  • feign micrometer 属性设置为 true(默认情况下)

    • spring.cloud.openfeign.micrometer.enabled=true(适用于所有客户端)

    • spring.cloud.openfeign.client.config.feignName.micrometer.enabled=true(适用于单个客户端)

备注

如果你的应用程序已经使用了 Micrometer,启用此功能就像将 feign-micrometer 添加到你的 classpath 中一样简单。

你也可以通过以下方式禁用该功能:

  • 从你的类路径中排除 feign-micrometer

  • 将其中一个 Feign Micrometer 属性设置为 false

    • spring.cloud.openfeign.micrometer.enabled=false

    • spring.cloud.openfeign.client.config.feignName.micrometer.enabled=false

备注

spring.cloud.openfeign.micrometer.enabled=false 会禁用所有 Feign 客户端的 Micrometer 支持,无论客户端级别的标志 spring.cloud.openfeign.client.config.feignName.micrometer.enabled 的值如何。如果你希望按客户端启用或禁用 Micrometer 支持,请不要设置 spring.cloud.openfeign.micrometer.enabled,而是使用 spring.cloud.openfeign.client.config.feignName.micrometer.enabled

你也可以通过注册自己的 bean 来自定义 MicrometerObservationCapability

@Configuration
public class FooConfiguration {
@Bean
public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) {
return new MicrometerObservationCapability(registry);
}
}
java

仍然可以在 Feign 中使用 MicrometerCapability(仅支持指标功能),你需要禁用 Micrometer 支持(spring.cloud.openfeign.micrometer.enabled=false)并创建一个 MicrometerCapability Bean:

@Configuration
public class FooConfiguration {
@Bean
public MicrometerCapability micrometerCapability(MeterRegistry meterRegistry) {
return new MicrometerCapability(meterRegistry);
}
}
java

Feign 缓存

如果使用了 @EnableCaching 注解,将会创建并注册一个 CachingCapability bean,以便你的 Feign 客户端能够识别其接口上的 @Cache* 注解:

public interface DemoClient {

@GetMapping("/demo/{filterParam}")
@Cacheable(cacheNames = "demo-cache", key = "#keyParam")
String demoEndpoint(String keyParam, @PathVariable String filterParam);
}
java

你也可以通过设置属性 spring.cloud.openfeign.cache.enabled=false 来禁用该功能。

Spring @RequestMapping 支持

Spring Cloud OpenFeign 提供了对 Spring @RequestMapping 注解及其派生注解(如 @GetMapping@PostMapping 等)的支持。@RequestMapping 注解上的属性(包括 valuemethodparamsheadersconsumesproduces)由 SpringMvcContract 解析为请求的内容。

考虑以下示例:

使用 params 属性定义一个接口。

@FeignClient("demo")
public interface DemoTemplate {

@PostMapping(value = "/stores/{storeId}", params = "mode=upsert")
Store update(@PathVariable("storeId") Long storeId, Store store);
}
java

在上面的例子中,请求 URL 被解析为 /stores/storeId?mode=upsert
params 属性也支持使用多个 key=value 或仅一个 key

  • params = { "key1=v1", "key2=v2" } 时,请求 URL 被解析为 /stores/storeId?key1=v1&key2=v2

  • params = "key" 时,请求 URL 被解析为 /stores/storeId?key

Feign 的 @QueryMap 支持

Spring Cloud OpenFeign 提供了一个等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数注解为查询参数映射。

例如,Params 类定义了参数 param1param2

// Params.java
public class Params {
private String param1;
private String param2;

// [Getters and setters omitted for brevity]
}
java

以下 Feign 客户端通过使用 @SpringQueryMap 注解来使用 Params 类:

@FeignClient("demo")
public interface DemoTemplate {

@GetMapping(path = "/demo")
String demoEndpoint(@SpringQueryMap Params params);
}
java

如果你需要对生成的查询参数映射进行更多控制,可以实现一个自定义的 QueryMapEncoder bean。

HATEOAS 支持

Spring 提供了一些 API 来创建遵循 HATEOAS 原则的 REST 表示,包括 Spring HateoasSpring Data REST

如果你的项目使用了 org.springframework.boot:spring-boot-starter-hateoas 启动器或 org.springframework.boot:spring-boot-starter-data-rest 启动器,Feign 的 HATEOAS 支持将默认启用。

当启用 HATEOAS 支持时,Feign 客户端可以序列化和反序列化 HATEOAS 表示模型:EntityModelCollectionModelPagedModel

@FeignClient("demo")
public interface DemoTemplate {

@GetMapping(path = "/stores")
CollectionModel<Store> getStores();
}
java

Spring @MatrixVariable 支持

Spring Cloud OpenFeign 提供了对 Spring @MatrixVariable 注解的支持。

如果将一个映射(map)作为方法参数传递,@MatrixVariable 路径段将通过使用 = 连接映射中的键值对来创建。

如果传递了一个不同的对象,则使用 =@MatrixVariable 注解中提供的 name(如果已定义)或注解的变量名称与提供的方法参数连接起来。

重要提示

尽管在服务器端,Spring 并不要求用户将路径段占位符的名称与矩阵变量的名称保持一致,因为这在客户端会显得过于模糊,但 Spring Cloud OpenFeign 要求您添加一个路径段占位符,其名称必须与 @MatrixVariable 注解中提供的 name(如果已定义)或注解的变量名称相匹配。

例如:

@GetMapping("/objects/links/{matrixVars}")
Map<String, List<String>> getObjects(@MatrixVariable Map<String, List<String>> matrixVars);
java

请注意,变量名和路径段占位符都称为 matrixVars

@FeignClient("demo")
public interface DemoTemplate {

@GetMapping(path = "/stores")
CollectionModel<Store> getStores();
}
java

Feign CollectionFormat 支持

我们通过提供 @CollectionFormat 注解来支持 feign.CollectionFormat。你可以通过将所需的 feign.CollectionFormat 作为注解值传递给 Feign 客户端方法(或整个类以影响所有方法)来使用它。

在以下示例中,使用 CSV 格式代替默认的 EXPLODED 来处理方法。

@FeignClient(name = "demo")
protected interface DemoFeignClient {

@CollectionFormat(feign.CollectionFormat.CSV)
@GetMapping(path = "/test")
ResponseEntity performRequest(String test);

}
java

响应式支持

在 Spring Cloud OpenFeign 活跃开发期间,OpenFeign 项目 并不支持响应式客户端,例如 Spring WebClient,因此这种支持也无法添加到 Spring Cloud OpenFeign 中。

由于 Spring Cloud OpenFeign 项目现已视为功能完备,即使上游项目提供了支持,我们也不计划添加。我们建议迁移到 Spring Interface Clients 替代。该方案同时支持阻塞式和响应式栈。

早期初始化错误

我们不建议在应用程序生命周期的早期阶段(如处理配置和初始化 bean 时)使用 Feign 客户端。在 bean 初始化期间使用客户端是不被支持的。

同样地,根据你使用 Feign 客户端的方式,你可能会在启动应用程序时看到初始化错误。为了解决这个问题,你可以在自动装配客户端时使用 ObjectProvider

@Autowired
ObjectProvider<TestFeignClient> testFeignClient;
java

Spring Data 支持

如果类路径中存在 Jackson Databind 和 Spring Data Commons,将会自动添加 org.springframework.data.domain.Pageorg.springframework.data.domain.Sort 的转换器。

要禁用此行为,请设置

spring.cloud.openfeign.autoconfiguration.jackson.enabled=false
java

详情请参见 org.springframework.cloud.openfeign.FeignAutoConfiguration.FeignJacksonConfiguration

Spring @RefreshScope 支持

如果启用了 Feign 客户端刷新,每个 Feign 客户端都会以以下方式创建:

  • feign.Request.Options 作为一个刷新作用域的 bean。这意味着诸如 connectTimeoutreadTimeout 等属性可以在任何 Feign 客户端实例上刷新。

  • 一个包装在 org.springframework.cloud.openfeign.RefreshableUrl 下的 URL。这意味着 Feign 客户端的 URL,如果通过 spring.cloud.openfeign.client.config.{feignName}.url 属性定义,可以在任何 Feign 客户端实例上刷新。

你可以通过 POST /actuator/refresh 来刷新这些属性。

默认情况下,Feign 客户端中的刷新行为是禁用的。使用以下属性来启用刷新行为:

spring.cloud.openfeign.client.refresh-enabled=true
java
提示

不要在 @FeignClient 接口上使用 @RefreshScope 注解。

OAuth2 支持

可以通过在项目中添加 spring-boot-starter-oauth2-client 依赖并设置以下标志来启用 OAuth2 支持:

spring.cloud.openfeign.oauth2.enabled=true

当标志设置为 true 并且存在 OAuth2 客户端上下文资源详细信息时,将创建一个 OAuth2AccessTokenInterceptor 类的 bean。在每次请求之前,拦截器会解析所需的访问令牌并将其作为请求头包含在内。OAuth2AccessTokenInterceptor 使用 OAuth2AuthorizedClientManager 来获取持有 OAuth2AccessTokenOAuth2AuthorizedClient。如果用户使用 spring.cloud.openfeign.oauth2.clientRegistrationId 属性指定了 OAuth2 的 clientRegistrationId,则将使用它来检索令牌。如果未检索到令牌或未指定 clientRegistrationId,则将使用从 url 主机段中检索到的 serviceId

提示

使用 serviceId 作为 OAuth2 客户端 registrationId 对于负载均衡的 Feign 客户端来说非常方便。对于非负载均衡的客户端,基于属性的 clientRegistrationId 则是一个合适的方法。

提示

如果你不想使用默认的 OAuth2AuthorizedClientManager 设置,你可以在配置中直接实例化一个该类型的 bean。

转换负载均衡的 HTTP 请求

你可以使用选定的 ServiceInstance 来转换负载均衡的 HTTP 请求。

对于 Request,你需要实现并定义 LoadBalancerFeignRequestTransformer,如下所示:

@Bean
public LoadBalancerFeignRequestTransformer transformer() {
return new LoadBalancerFeignRequestTransformer() {

@Override
public Request transformRequest(Request request, ServiceInstance instance) {
Map<String, Collection<String>> headers = new HashMap<>(request.headers());
headers.put("X-ServiceId", Collections.singletonList(instance.getServiceId()));
headers.put("X-InstanceId", Collections.singletonList(instance.getInstanceId()));
return Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(),
request.requestTemplate());
}
};
}
java

如果定义了多个转换器,它们将按照 bean 定义的顺序应用。或者,你可以使用 LoadBalancerFeignRequestTransformer.DEFAULT_ORDER 来指定顺序。

X-Forwarded 头部支持

可以通过设置以下标志来启用 X-Forwarded-HostX-Forwarded-Proto 支持:

spring.cloud.loadbalancer.x-forwarded.enabled=true
properties

支持的方式为 Feign 客户端提供 URL

你可以通过以下任一方式为 Feign 客户端提供 URL:

情况示例详情
URL 在 @FeignClient 注解中提供。@FeignClient(name="testClient", url="http://localhost:8081")URL 从注解的 url 属性解析,不进行负载均衡。
URL 在 @FeignClient 注解和配置属性中都提供。@FeignClient(name="testClient", url="http://localhost:8081") 并且在 application.yml 中定义的属性为 spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081URL 从注解的 url 属性解析,不进行负载均衡。配置属性中提供的 URL 未被使用。
URL 未在 @FeignClient 注解中提供,但在配置属性中提供。@FeignClient(name="testClient") 并且在 application.yml 中定义的属性为 spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081URL 从配置属性解析,不进行负载均衡。如果 spring.cloud.openfeign.client.refresh-enabled=true,则配置属性中定义的 URL 可以刷新,如 Spring RefreshScope 支持 中所述。
URL 既未在 @FeignClient 注解中提供,也未在配置属性中提供。@FeignClient(name="testClient")URL 从注解的 name 属性解析,并进行负载均衡。

AOT 和原生镜像支持

Spring Cloud OpenFeign 支持 Spring AOT 转换和原生镜像,但仅在禁用刷新模式、禁用 Feign 客户端刷新(默认设置)以及禁用 延迟 @FeignClient 属性解析(默认设置)的情况下支持。

注意

如果你想在 AOT 或原生镜像模式下运行 Spring Cloud OpenFeign 客户端,请确保将 spring.cloud.refresh.enabled 设置为 false

提示

如果你想在 AOT 或原生镜像模式下运行 Spring Cloud OpenFeign 客户端,请确保 spring.cloud.openfeign.client.refresh-enabled 未被设置为 true

提示

如果你想在 AOT 或原生镜像模式下运行 Spring Cloud OpenFeign 客户端,请确保 spring.cloud.openfeign.lazy-attributes-resolution 未设置为 true

提示

然而,如果你通过属性设置了 url 值,可以通过在运行镜像时使用 -Dspring.cloud.openfeign.client.config.[clientId].url=[url] 标志来覆盖 @FeignClienturl 值。为了启用覆盖功能,在构建时还必须通过属性设置 url 值,而不是通过 @FeignClient 属性。

配置属性

要查看所有与 Spring Cloud OpenFeign 相关的配置属性列表,请查看附录页面