Spring Cloud OpenFeign 功能

修改于 2024年12月18日
31分钟阅读
Spring Cloud OpenFeign
"
"

该项目通过自动配置和绑定到 Spring Environment 和其他 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,提供了负载均衡的 http 客户端来使用 Feign。

怎样去引入Feign

要在项目中引入 Feign,请使用group: org.springframework.cloud 和artifact id: spring-cloud-starter-openfeign。有关使用当前 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
StoreClient.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 的阻塞模式可用的所有功能。您可以在 project documentation 中阅读更多有关的信息。

提示

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

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

警告

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

属性解析模式

在创建 Feign 客户端 bean 时,我们会解析通过 @FeignClient 注释传递的值。从 4.x 开始 ,这些值会被提前解析。这对大多数用例来说,这是一个很好的解决方案,并且它还支持 AOT (提前编译)模式。

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

覆盖 Feign Defaults

Spring Cloud 的 Feign 支持的一个核心概念是命名客户端。每个Feign客户端都是一组组件的一部分,这些组件协同工作,按需联系远程服务器,并且集合具有一个名称,您可以使用 @FeignClient 注释为其指定名称。Spring Cloud 使用 FeignClientsConfiguration 为每个命名客户端按需创建一个新的集成作为 ApplicationContext 。这包含(除其他外) feign.Decoderfeign.Encoderfeign.Contract 。可以使用 contextId 注解的 @FeignClient 属性覆盖该系组的名称。

Spring Cloud 允许通过使用 @FeignClient 来声明其他配置(通过配置 FeignClientsConfiguration)来完全控制 Feign 客户端。例:

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

在这种情况下,客户端由 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 {
    //..
}
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 位于 Classpath 上,则使用 FeignBlockingLoadBalancerClient 。如果它们都不在 Classpath 上,则使用默认的 Feign 客户端。
注意

spring-cloud-starter-openfeign 支持 spring-cloud-starter-loadbalancer 。但是,与可选依赖项一样,如果要使用它,则需要确保已将其添加到项目中。

要使用 OkHttpClient 支持的 Feign 客户端和 Http2Client Feign 客户端,请确保要使用的客户端位于 Classpath 上,并分别将 spring.cloud.openfeign.okhttp.enabledspring.cloud.openfeign.http2client.enabled 设置为 true

对于 Apache HttpClient 5 支持的 Feign 客户端,要确保 HttpClient 5 在 Classpath 上,但仍然可以通过将 spring.cloud.openfeign.httpclient.hc5.enabled 设置为 false 来禁用它对 Feign Clients 的使用。在使用 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,以 httpclient.http2 为前缀的适用于 Http2Client。您可以在附录中找到可自定义的属性的完整列表。如果无法使用 properties 配置 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 默认行为中,它将自动重试 IOException,将它们视为临时的网络相关异常,以及从 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 也可以使用配置属性进行配置。

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
yml

在这个示例中的 feignName 是指 @FeignClient value ,它也作为 @FeignClient name@FeignClient contextId 的 别名。在负载均衡方案中,它还对应于将用于检索实例的服务器应用程序的 serviceId 。解码器、重试器和其他解码器的指定类必须在Spring上下文中具有bean或具有默认构造函数。

默认配置可以在 @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
yml

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

如果我们想创建多个具有相同名称或 url 的Feign客户端,以便它们指向同一个服务器,但每个客户端具有不同的自定义配置,那么我们必须使用 @FeignClient 的 contextId 属性,以避免这些配置 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

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

超时处理

我们可以在默认客户端和命名客户端上进行超时配置。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.classSpring Cloud OpenFeign 提供的默认配置。

注意

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

注意

自动装配的 Contract bean 提供了对 SpringMVC 注释的支持,使得Feign Contract 对象定义哪些注释和值在接口上有效,而不是默认的 Feign 本机注释。不建议将 Spring MVC 注释和本机 Feign 注释混合在一起。

您还可以在 Builder 上使用 Builder 配置 FeignClient 而不是从父上下文继承 bean。你可以通过覆盖声明来实现这一点 inheritParentContext(false)

Feign Spring Cloud CircuitBreaker 支持

如果 Spring Cloud CircuitBreaker 位于 Classpath 和 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 ,熔断器名称可以保留旧模式。

提供 bean CircuitBreakerNameResolver ,您可以更改断路器名称模式。

@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 )。

使用配置属性配置 CircuitBreaker

您可以通过配置属性配置 CircuitBreaker。

例如,如果您有这个 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
yml
注意

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

Feign Spring Cloud CircuitBreaker 回退

Spring Cloud CircuitBreaker 支持回退的概念:当 circuit 打开或出现错误时执行的默认代码位置。要为给定的 @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

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

@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,也没有一个标记为 primary。为了解决这个问题, Spring Cloud OpenFeign 将所有 Feign 实例标记为 @Primary ,因此 Spring Framework 会知道要将哪个 bean注入。在某些情况下,这可能并不可取。如果要关闭此行为,请将 primary@FeignClient 属性设置为 false

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

Feign Inheritance 支持

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

UserService.java
public interface UserService {

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

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

}
java
警告

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

Feign 请求/响应压缩

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

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

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
properties

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

当请求与 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-encoding 或 accept-encoding 标头,则禁用该压缩,因此当 feign.okhttp.OkHttpClient 存在于 Classpath 上且 spring.cloud.openfeign.okhttp.enabled 设置为 true 时,我们不会启用压缩。

Feign 日志

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

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

您可以为每个客户端配置的 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 Capability 支持

Feign 功能公开了核心 Feign 组件,以便可以修改这些组件。例如,这些功能可以获取客户端 ,装饰它,并将装饰的实例返回给 Feign。对 Micrometer 的支持就是一个很好的真实案例。请参阅 Micrometer Support

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

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

Micrometer 支持

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

  • feign-micrometer 位于 Classpath 上
  • ObservationRegistry bean 可用
  • Feign Micrometer 属性设置为 true (默认情况下)
    • spring.cloud.openfeign.micrometer.enabled=true (适用于所有客户端)
    • spring.cloud.openfeign.client.config.feignName.micrometer.enabled=true (适用于单个客户端)
注意

如果您的应用程序已经使用 Micrometer,则启用此功能就像将 feign-micrometer 放在 Classpath 上一样轻松。

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

  • 从 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

仍然可以将 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);
    }
}
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 客户端通过使用 Params 注释来使用 @SpringQueryMap 类:

@FeignClient("demo")
public interface DemoTemplate {

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

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

HATEOAS 支持

Spring 提供了一些 API 来创建遵循 HATEOAS 原则、Spring HateoasSpring Data REST 的 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 作为 method 参数传递,则通过使用 @MatrixVariable 连接映射中的键值对来创建 = 路径段。

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

重要

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

例如:

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

请注意,变量 name 和路径段占位符都称为 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。那里支持阻塞和响应式堆栈。

早期初始化错误

我们不鼓励在应用程序生命周期的早期阶段使用 Feign 客户端,同时处理配置和初始化 bean。不支持在 bean 初始化期间使用 clients。

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

@Autowired
ObjectProvider<TestFeignClient> testFeignClient;
java

Spring Data 支持

如果 Jackson Databind 和 Spring Data Commons 在 Classpath 上,则将自动添加 org.springframework.data.domain.Pageorg.springframework.data.domain.Sort 的转换器。

要禁用此行为,请将

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

有关详细信息,请参阅 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
properties
提示

请勿使用 @FeignClient 注释注释 @RefreshScope 接口。

OAuth2 支持

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

spring.cloud.openfeign.oauth2.enabled=true
properties

当标志设置为 true 并且存在 oauth2 客户端上下文资源详细信息时,将创建类 OAuth2AccessTokenInterceptor 的 Bean。在每个请求之前,侦听器会解析所需的访问令牌并将其作为标头包含在内。 OAuth2AccessTokenInterceptor 使用 OAuth2AuthorizedClientManager 获取包含 OAuth2AccessTokenOAuth2AuthorizedClient 。如果用户使用 spring.cloud.openfeign.oauth2.clientRegistrationId 属性指定了 OAuth2 clientRegistrationId ,它将用于检索令牌。如果未检索到令牌或未指定 clientRegistrationId ,则将使用从 url 主机 Segment 中检索到的 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 ,则可以按照 [Spring RefreshScope 支持](#Spring RefreshScope 支持) 中所述刷新配置属性中定义的URL。
该 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 。

提示

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

properties 配置属性

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