JiaHe's Blog

读万卷书,行万里路

Spring Cloud OpenFeign 中文翻译

Spring Cloud OpenFeign

4.0.2

该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型,为 Spring Boot 应用程序提供 OpenFeign 集成。

声明式 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,请使用带有组 org.springframework.cloud 和工件 ID spring-cloud-starter-openfeign 的启动器。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud Project 页面

示例 Spring Boot 应用程序

Application.java
@SpringBootApplication
@EnableFeignClients
public class Application {

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

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

@RequestMapping(method = RequestMethod.GET, value = "/stores")
Page<Store> getStores(Pageable pageable);

@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
Store update(@PathVariable("storeId") Long storeId, Store store);

@RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
void delete(@PathVariable Long storeId);
}

@FeignClient 注解中,字符串值(上面的“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)

属性解析方式

在创建 Feign 客户端 bean 时,我们解析通过 @FeignClient 注释传递的值。从 4.x 开始,这些值正在急切地得到解决。对于大多数用例来说,这是一个很好的解决方案,它还允许 AOT 支持。

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

对于 Spring Cloud Contract 测试集成,应该使用lazy-attributes-resolution

覆盖默认配置

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 {
//..
}

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

FooConfiguration 不需要用 @Configuration 注释。但是,如果是,则注意将其从任何 @ComponentScan 中排除,否则将包含此配置,因为在指定时它将成为 feign.Decoderfeign.Encoderfeign.Contract 等的默认源。这可以通过将它放在与任何 @ComponentScan@SpringBootApplication 分开的、不重叠的包中来避免,或者它可以在 @ComponentScan 中明确排除。

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

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

nameurl 属性支持占位符。

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

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 。如果它们都不在类路径中,则使用默认的feignClient。

spring-cloud-starter-openfeign 支持 spring-cloud-starter-loadbalancer 。但是,作为可选依赖项,如果要使用它,您需要确保它已添加到您的项目中。

OkHttpClient 和 Apache HttpClient 5 Feign 客户端可以通过分别将 spring.cloud.openfeign.okhttp.enabledspring.cloud.openfeign.httpclient.hc5.enabled 设置为 true 并将它们放在类路径中来使用。在使用 Apache HC5 时,您可以通过提供 org.apache.hc.client5.http.impl.classic.CloseableHttpClient 的 bean 来自定义使用的 HTTP 客户端。

您可以通过在 spring.cloud.openfeign.httpclient.xxx 属性中设置值来进一步自定义 http 客户端。仅以 httpclient 为前缀的将适用于所有客户端,以 httpclient.hc5 为前缀的适用于 Apache HttpClient 5,以 httpclient.okhttp 为前缀的适用于 OkHttpClient。您可以在附录中找到可以自定义的属性的完整列表。

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

Spring Cloud OpenFeign默认不为feign提供以下bean,但还是会从application context中查找这些类型的bean来创建feign client:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory
  • QueryMapEncoder
  • Capability (默认提供 MicrometerObservationCapabilityCachingCapability

默认情况下会创建 Retryer 类型的 Retryer.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");
}
}

这会将 SpringMvcContract 替换为 feign.Contract.Default 并将 RequestInterceptor 添加到 RequestInterceptor 的集合中。

@FeignClient 也可以使用配置属性进行配置。

application.yml
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

此示例中的 feignName 指的是 @FeignClient value ,它也是 @FeginClient name@FeignClient contextId 的别名。在负载均衡的场景中,它还对应于将用于检索实例的服务器应用程序的 serviceId

可以按照与上述类似的方式在 @EnableFeignClients 属性 defaultConfiguration 中指定默认配置。不同之处在于,此配置将适用于所有 feign 客户端。

如果您更喜欢使用配置属性来配置所有 @FeignClient ,则可以使用 default feign 名称创建配置属性。

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

application.yml
spring:
cloud:
openfeign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic

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

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

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

也可以将 FeignClient 配置为不从父上下文继承 bean。您可以通过覆盖 FeignClientConfigurer bean 中的 inheritParentConfiguration() 以返回 false 来做到这一点:

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

}
}

默认情况下,Feign 客户端不对斜杠 / 字符进行编码。您可以通过将 spring.cloud.openfeign.client.decodeSlash 的值设置为 false 来更改此行为。

SpringEncoder 配置

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

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

Timeout 处理

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

  • connectTimeout 防止由于服务器处理时间长而阻塞调用者。
  • readTimeout 从建立连接开始应用,当返回响应时间过长时触发。

如果服务器未运行或不可用,则数据包会导致连接被拒绝。通信以错误消息或回退结束。如果设置得非常低,这可能会在 connectTimeout 之前发生。执行查找和接收此类数据包所花费的时间会导致此延迟的很大一部分。它可能会根据涉及 DNS 查找的远程主机而发生变化。

手动创建 Feign Clients

在某些情况下,可能需要以使用上述方法无法实现的方式自定义 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");
}
}

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

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

Feign Contract 对象定义了哪些注释和值在接口上有效。自动装配的 Contract bean 提供对 SpringMVC 注释的支持,而不是默认的 Feign 本机注释。

您还可以使用Builder来配置FeignClient,使其不从父上下文继承bean。你可以通过重写Builder上的inheritParentContext(false) 来实现这一点。

支持 Feign Spring Cloud CircuitBreaker

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

要在每个客户端的基础上禁用 Spring Cloud CircuitBreaker 支持,请创建一个带有“原型”范围的香草 Feign.Builder

例如:

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

断路器名称遵循此模式 <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();
}
}

要启用 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();
}

你可以像如下这样通过配置项进行配置

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

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

Feign Spring Cloud CircuitBreaker Fallbacks

Spring Cloud CircuitBreaker支持fallback(回退)的概念:当Circuit启用或出现错误时执行的默认代码路径。要为给定的 @FeignClient 启用fallback功能的话,需要将 fallback 属性设置为实现fallback的类名。您还需要将您的实现声明为 Spring bean。

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

@RequestMapping(method = RequestMethod.GET, value = "/hello")
Hello getHello();

@RequestMapping(method = RequestMethod.GET, value = "/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";
}

}

如果需要操作导致fallback的cause,可以使用 @FeignClient 中的 fallbackFactory 属性。

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

@RequestMapping(method = RequestMethod.GET, value = "/hello")
Hello getHello();

@RequestMapping(method = RequestMethod.GET, value = "/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";
}

}

Feign and @Primary

将 Feign 与 Spring Cloud CircuitBreaker fallbacks 一起使用时, ApplicationContext 中有多个相同类型的 bean。这将导致 @Autowired 无法工作,因为不完全是一个 bean,或者一个被标记为主要的。为了解决这个问题,Spring Cloud OpenFeign 将所有 Feign 实例标记为 @Primary ,因此 Spring Framework 将知道要注入哪个 bean。在某些情况下,这可能是不可取的。要关闭此行为,请将 @FeignClientprimary 属性设置为 false。

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

Feign 支持继承

Feign 通过单继承接口支持样板 API。这允许将常见操作分组到方便的基本接口中。

UserService.java
public interface UserService {

@RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
User getUser(@PathVariable("id") long id);
}
UserResource.java
@RestController
public class UserResource implements UserService {

}
UserClient.java
package project.user;

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

}

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

Feign 压缩请求/响应

您可以考虑为您的 Feign 请求启用请求或响应 GZIP 压缩。您可以通过启用以下属性之一来执行此操作:

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

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

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

由于 OkHttpClient 使用 “transparent” 压缩,如果 content-encodingaccept-encoding 标头存在则禁用,因此当类路径上存在 feign.okhttp.OkHttpClientspring.cloud.openfeign.okhttp.enabled 设置为 true 时,我们不启用压缩。

Feign logging

为每个创建的 Feign 客户端创建一个记录器。默认情况下,logger的名称使用的是创建 Feign 客户端的接口的完整类名。 Feign logging 只响应 DEBUG 级别。

application.yml
logging.level.project.user.UserClient: DEBUG

您可以为每个客户端配置的 Logger.Level 对象告诉 Feign 要记录多少。选项是:

  • NONE ,无日志记录(默认)。
  • BASIC ,只记录请求方法和URL以及响应状态码和执行时间。
  • HEADERS ,记录基本信息以及请求和响应标头。
  • FULL ,记录请求和响应的标头、正文和元数据。

例如,以下内容会将 Logger.Level 设置为 FULL

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

支持 Feign Capability

The Feign capabilities expose core Feign components so that these components can be modified. For example, the capabilities can take the Client, decorate it, and give the decorated instance back to Feign. The support for Micrometer is a good real-life example for this. See Micrometer Support.

Feign Capability 公开核心Feign组件,以便可以修改这些组件。例如,Capability 可以接受 Client装饰它,并将装饰后的实例返回给Feign。对Micrometer的支持就是一个很好的现实例子。参见Micrometer Support

创建一个或多个 Capability beans 并将它们放置在 @FeignClient 配置中允许您注册它们并修改相关客户端的行为。

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

支持 Micrometer

如果满足以下所有条件,则会创建并注册一个 MicrometerObservationCapability bean,以便 Micrometer 可以观察到您的 Feign 客户端:

  • 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 放入您的类路径一样简单。

您还可以通过以下任一方式禁用该功能:

  • 从你的类路径中排除 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);
}
}

仍然可以将 MicrometerCapability 与 Feign(仅支持指标)一起使用,您需要禁用 Micrometer 支持( spring.cloud.openfeign.micrometer.enabled=false )并创建一个 MicrometerCapability bean:

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

Feign Caching

如果使用 @EnableCaching 注解,就会创建并注册一个 CachingCapability bean,这样你的Feign客户端就可以在它的接口上识别 @Cache* 注解:

public interface DemoClient {

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

您还可以通过属性 spring.cloud.openfeign.cache.enabled=false 禁用该功能。

支持 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]
}

下面的 feign 客户端通过使用 @SpringQueryMap 注解来使用 Params 类:

@FeignClient("demo")
public interface DemoTemplate {

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

如果您需要更多地控制生成的查询参数映射,您可以实现自定义 QueryMapEncoder bean。

支持 HATEOAS

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

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

启用 HATEOAS 支持后,允许 Feign 客户端序列化和反序列化 HATEOAS 表示模型:EntityModel](https://docs.spring.io/spring-hateoas/docs/1.0.0.M1/apidocs/org/springframework/hateoas/EntityModel.html), CollectionModel and PagedModel

@FeignClient("demo")
public interface DemoTemplate {

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

支持 Spring @MatrixVariable

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

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

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

  • IMPORTANT

    即使在服务器端,Spring 不要求用户将路径段占位符命名为与矩阵变量名称相同,因为它在客户端太模糊了,Spring Cloud OpenFeign 要求您添加一个路径段占位符与 @MatrixVariable 注释(如果已定义)中提供的 name 或带注释的变量名称相匹配的名称。

For example:

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

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

@FeignClient("demo")
public interface DemoTemplate {

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

支持 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);

}

支持 Reactive

由于 OpenFeign 项目目前不支持响应式客户端,例如 Spring WebClient,Spring Cloud OpenFeign 也不支持。一旦核心项目可用,我们将在此处添加对它的支持。

在此之前,我们建议使用 feign-reactive 来支持 Spring WebClient。

启动初始化报错

根据您使用 Feign 客户端的方式,您可能会在启动应用程序时看到初始化错误。要解决此问题,您可以在自动装配客户端时使用 ObjectProvider

@Autowired
ObjectProvider<TestFeignClient> testFeignClient;

支持 Spring Data

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

禁用此行为

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

更多细节参考 org.springframework.cloud.openfeign.FeignAutoConfiguration.FeignJacksonConfiguration

支持 Spring @RefreshScope

如果启用了 Feign 客户端刷新,则创建每个 Feign 客户端时:

  • feign.Request.Options 作为刷新范围的 bean。这意味着可以针对任何 Feign 客户端实例刷新诸如 connectTimeoutreadTimeout 之类的属性。
  • 包裹在 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

不要使用 @RefreshScope 注释来注释 @FeignClient 接口。

支持 OAuth2

可以通过设置以下标志启用 OAuth2 支持:

spring.cloud.openfeign.oauth2.enabled=true

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

  • TIP

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

  • TIP

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

Transform the load-balanced HTTP request

您可以使用选定的 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());
}
};
}

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

支持 X-Forwarded Headers

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

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

支持多种向Feign Client提供URL的方式

您可以通过以下任何一种方式向 Feign 客户端提供 URL:

CaseExampleDetails
该 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 ,那么可以按照 Spring RefreshScope Support 中的描述刷新配置属性中定义的 URL。
@FeignClient 注释和配置属性中均未提供该 URL。@FeignClient(name="testClient")URL 是从注解的 name 属性中解析出来的,具有负载均衡。

支持 AOT and Native Image

Spring Cloud OpenFeign 支持 Spring AOT 转换和原生图像,但是,仅在禁用刷新模式、禁用 Feign 客户端刷新(默认设置)和禁用 lazy @FeignClient attribute resolution(默认设置)的情况下。

如果要在 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] 标志运行图像来覆盖 @FeignClient url 值。为了启用覆盖, url 值还必须在构建期间通过属性设置,而不是 @FeignClient 属性。

配置属性

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