当前位置: 首页 > news >正文

OpenFeign使用详解

什么是OpenFeign?

OpenFeign 是一个声明式的 HTTP 客户端,旨在简化微服务架构中不同服务之间的 HTTP 调用。它通过集成 Ribbon 实现了客户端负载均衡,并且能够与 Eureka、Consul 等服务发现组件无缝对接。使用 OpenFeign,开发者只需定义接口并使用注解来配置 HTTP 请求,从而避免了编写大量的模板代码。

cloud官网介绍Feign:Spring Cloud OpenFeign

OpenFeign源码:GitHub - OpenFeign/feign: Feign makes writing java http clients easier

Feign 的实现

Feign 在 Ribbon + RestTemplate 的基础上进行了进一步封装,帮助开发者定义和实现依赖服务的接口。通过 Feign,开发者只需创建一个接口并使用注解进行配置,即可完成对服务提供方的接口绑定,简化了使用 Spring Cloud Ribbon 时自动封装服务调用客户端的开发工作。

Feign 和 OpenFeign 的区别

特性FeignOpenFeign
依赖<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>    
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
作用轻量级 RESTful HTTP 服务客户端,内置 Ribbon 用于客户端负载均衡,调用服务注册中心的服务。在 Feign 的基础上支持 SpringMVC 的注解(如 @RequestMapping),通过动态代理生成实现类,实现负载均衡并调用其他服务。

OpenFeign 的优点

  1. 声明式调用:通过注解定义 HTTP 请求,代码更加简洁和易读。

  2. 集成 Ribbon:支持客户端负载均衡,确保请求在多个服务实例之间均匀分布。

  3. 支持服务发现:与 Eureka、Consul 等服务发现组件无缝集成,自动发现和调用服务。

  4. 支持熔断:与 Hystrix、Sentinel 等熔断器集成,提升系统的稳定性和容错能力。

  5. 可扩展性:支持自定义拦截器、编码器和解码器,便于根据需求进行扩展和定制化。

基本用法

父项目的 pom.xml 文件定义了所有子模块共享的依赖和插件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.9</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>cloud</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging> <!-- 这里设置为pom --><name>demo</name><description>demo</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version><spring-cloud.version>2023.0.2</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-dependencies --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2023.0.1.0</version><type>pom</type></dependency><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>4.1.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><!-- 定义子模块 --><modules><module>service1</module><module>service2</module><module>common</module></modules></project>

子项目 common

common 是一个简单的 Spring Boot 服务,提供一个 REST API。

ServiceBController.java

package com.example.common.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ServiceBController {@GetMapping("/api/resource")public String getResource() {return "来自服务c的问候!";}
}

子项目 service-a

service1 使用 OpenFeign 调用 service-b 的服务。

Service1Application.java

在启动类,加上 @EnableFeignClients 注解。

package cloud.service1;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients
public class Service1Application {public static void main(String[] args) {SpringApplication.run(Service1Application.class, args);}}

ServiceBClient.java

package cloud.service1.client;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;@FeignClient(name = "service-b", url = "http://localhost:8080")
public interface ServiceBClient {@GetMapping("/api/resource")String getResource();
}

ServiceAController.java 

package cloud.service1.controller;import cloud.service1.client.ServiceBClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ServiceAController {private final ServiceBClient serviceBClient;public ServiceAController(ServiceBClient serviceBClient) {this.serviceBClient = serviceBClient;}@GetMapping("/api/resource")public String getResource() {return serviceBClient.getResource();}
}

如图所示,证明已经访问成功了。

@FeignClient 标签的常用属性 

@FeignClient 注解是 Spring Cloud OpenFeign 中用于声明一个 Feign 客户端的核心注解。它提供了丰富的属性来配置 Feign 客户端的行为,以满足不同场景下的微服务调用需求。

1、name

  • 类型: String
  • 描述: 指定 Feign 客户端调用的服务名称。这是一个必填属性,通常是注册在服务发现(如 Nacos)中的服务名。
@FeignClient(name = "demo-user")
public interface UserClient {// ...
}

2、url

  • 类型: String
  • 描述: 指定服务的 URL,通常用于调试或服务未注册到服务发现时。url 属性会覆盖 name 属性。
@FeignClient(name = "demo-user", url = "http://localhost:8080")
public interface UserClient {// ...
}

3、configuration

  • 类型: Class<?>[]
  • 描述: 指定自定义配置类,配置类可以用来定制 Feign 客户端的行为,如请求拦截器、编码器和解码器等。
@FeignClient(name = "demo-user", configuration = FeignConfig.class)
public interface UserClient {// ...
}

配置类示例:

@Configuration
public class FeignConfig {@Beanpublic RequestInterceptor requestInterceptor() {return template -> template.header("Custom-Header", "CustomHeaderValue");}
}

4、fallback

  • 类型: Class<?>
  • 描述: 指定服务降级的实现类。当 Feign 客户端调用失败时,会调用 fallback 指定的类中的方法。
@FeignClient(name = "demo-user", fallback = UserClientFallback.class)
public interface UserClient {// ...
}

5、fallbackFactory

  • 类型: Class<?>
  • 描述: 指定服务降级的工厂类,该工厂类可以提供更多的上下文信息,例如异常信息。
@FeignClient(name = "demo-user", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {// ...
}

6、path

  • 类型: String
  • 描述: 指定服务的统一前缀路径,在定义 Feign 接口的方法时可以省略该路径。
@FeignClient(name = "demo-user", path = "/api/users")
public interface UserClient {@GetMapping("/{id}")User getUserById(@PathVariable("id") Long id);
}

7、decode404

  • 类型: boolean
  • 描述: 指定是否将 HTTP 404 响应解码为 Feign 客户端的 fallback,默认值为 false。
@FeignClient(name = "demo-user", decode404 = true)
public interface UserClient {// ...
}

8、primary

  • 类型: boolean
  • 描述: 指定该 Feign 客户端是否为主要的 @Primary Bean,这对某些场景下的自动装配很有用,默认值为 true。
@FeignClient(name = "demo-user", primary = false)
public interface UserClient {// ...
}

9、contextId

  • 类型: String
  • 描述: 用于在多 Feign 客户端实例中区分不同的上下文 ID。特别适用于多个 Feign 客户端指向同一服务时的配置。
@FeignClient(name = "demo-user", contextId = "userClient1")
public interface UserClient1 {// ...
}@FeignClient(name = "demo-user", contextId = "userClient2")
public interface UserClient2 {// ...
}

添加请求头信息

在 Spring Cloud OpenFeign 中,可以通过多种方式添加请求头信息。以下是三种常见的方法:

1. 在方法参数上添加请求头信息

可以在 Feign 客户端接口的方法参数上使用 @RequestHeader 注解来添加请求头信息。

@FeignClient(name = "demo-user")
public interface UserClient {@GetMapping("/api/users/{id}")User getUserById(@PathVariable("id") Long id, @RequestHeader("Custom-Header") String customHeader);
}

2. 使用 Feign 配置类定义请求拦截器

如果需要在所有请求中添加相同的请求头,可以通过定义一个 Feign 请求拦截器来实现。

定义 Feign 配置类:

@Configuration
public class FeignConfig {@Beanpublic RequestInterceptor requestInterceptor() {return requestTemplate -> {requestTemplate.header("Custom-Header", "CustomHeaderValue");requestTemplate.header("Another-Header", "AnotherHeaderValue");};}
}

在 Feign 客户端中使用配置类: 

@FeignClient(name = "demo-user", configuration = FeignConfig.class)
public interface UserClient {@GetMapping("/api/users/{id}")User getUserById(@PathVariable("id") Long id);
}

3. 动态添加请求头信息

如果需要根据某些条件动态添加请求头信息,可以在拦截器中编写逻辑。

定义 Feign 配置类:

@Configuration
public class FeignConfig {@Beanpublic RequestInterceptor requestInterceptor() {return requestTemplate -> {// 动态添加请求头信息String customHeaderValue = getCustomHeaderValue();requestTemplate.header("Custom-Header", customHeaderValue);};}private String getCustomHeaderValue() {// 根据某些条件动态生成请求头值return "DynamicHeaderValue";}
}

在 Feign 客户端中使用配置类:

@FeignClient(name = "demo-user", configuration = FeignConfig.class)
public interface UserClient {@GetMapping("/api/users/{id}")User getUserById(@PathVariable("id") Long id);
}

超时控制

在 Spring Cloud OpenFeign 中,超时控制是非常重要的,特别是在微服务架构中,确保服务之间的调用不会因为超时而导致整个系统的不稳定。OpenFeign 提供了两种超时参数:connectTimeout 和 readTimeout,分别用于控制连接超时和读取超时。

第一步:提供方接口,制造超时场景

首先,我们需要在提供方接口中制造一个超时场景,以便在消费方调用时能够触发超时。

@RestController
@RequestMapping("/api/users")
public class UserController {@GetMapping("/{id}")public User getUserById(@PathVariable Long id) throws InterruptedException {// 模拟超时场景Thread.sleep(5000); // 休眠 5 秒return new User(id, "John Doe");}
}

第二步:消费方接口调用

在消费方接口中调用提供方接口,并配置超时参数。

@FeignClient(name = "demo-user", url = "http://localhost:8080")
public interface UserClient {@GetMapping("/api/users/{id}")User getUserById(@PathVariable("id") Long id);
}

第三步:超时处理

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

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

配置超时参数

可以通过配置文件(如 application.yml 或 application.properties)来设置超时参数。

示例:application.yml

feign:client:config:default:connectTimeout: 2000  # 连接超时时间,单位为毫秒readTimeout: 3000     # 读取超时时间,单位为毫秒

示例:application.properties

feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=3000

手动创建 Feign Client

在 Spring Cloud OpenFeign 中,通常使用 @FeignClient 注解来声明一个 Feign 客户端。然而,有时可能需要手动创建 Feign 客户端,例如在某些特殊场景下,或者需要更细粒度的控制。

示例代码

定义 Feign 接口

首先,定义一个标准的 Feign 接口。

public interface FooClient {@GetMapping("/api/foo")String getFoo();
}

手动创建 Feign 客户端

使用 Feign Builder API 手动创建两个 Feign 客户端实例,并为每个客户端配置不同的请求拦截器。

import feign.Feign;
import feign.auth.BasicAuthRequestInterceptor;
import feign.Client;
import feign.Contract;
import feign.Encoder;
import feign.Decoder;
import feign.micrometer.MicrometerObservationCapability;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.RestController;// 导入 Spring Cloud OpenFeign 提供的默认配置
@Import(FeignClientsConfiguration.class)
@RestController
public class FooController {// 定义两个 Feign 客户端实例private FooClient fooClient;private FooClient adminClient;// 自动注入 Feign 所需的组件@Autowiredpublic FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) {// 创建第一个 Feign 客户端实例,配置用户认证this.fooClient = Feign.builder().client(client) // 设置客户端.encoder(encoder) // 设置编码器.decoder(decoder) // 设置解码器.contract(contract) // 设置契约(注解解析器).addCapability(micrometerObservationCapability) // 添加 Micrometer 观测能力.requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) // 设置请求拦截器,使用用户认证.target(FooClient.class, "https://PROD-SVC"); // 指定目标服务 URL// 创建第二个 Feign 客户端实例,配置管理员认证this.adminClient = Feign.builder().client(client) // 设置客户端.encoder(encoder) // 设置编码器.decoder(decoder) // 设置解码器.contract(contract) // 设置契约(注解解析器).addCapability(micrometerObservationCapability) // 添加 Micrometer 观测能力.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) // 设置请求拦截器,使用管理员认证.target(FooClient.class, "https://PROD-SVC"); // 指定目标服务 URL}// 示例方法,使用 fooClient 和 adminClientpublic void exampleMethod() {String fooResponse = fooClient.getFoo(); // 调用用户认证的 Feign 客户端String adminResponse = adminClient.getFoo(); // 调用管理员认证的 Feign 客户端System.out.println("Foo Response: " + fooResponse);System.out.println("Admin Response: " + adminResponse);}
}

Feign Spring Cloud CircuitBreaker 的支持

Spring Cloud OpenFeign 提供了对 Spring Cloud CircuitBreaker 的支持,使得在 Feign 客户端中可以轻松集成熔断器(Circuit Breaker)功能。通过配置,可以全局启用或禁用 CircuitBreaker 支持,并且可以自定义 CircuitBreaker 的名称模式。

启用 Spring Cloud CircuitBreaker 支持

如果 Spring Cloud CircuitBreaker 在 classpath 上,并且 spring.cloud.openfeign.circuitbreaker.enabled=true,Feign 将用 CircuitBreaker 来包装所有方法。

示例配置

spring:cloud:openfeign:circuitbreaker:enabled: true

禁用特定客户端的 CircuitBreaker 支持

为了在每个客户端的基础上禁用 Spring Cloud CircuitBreaker 的支持,可以创建一个具有 "prototype" scope 的 Feign.Builder。

import feign.Feign;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;@Configuration
public class FooConfiguration {@Bean@Scope("prototype")public Feign.Builder feignBuilder() {return Feign.builder();}
}

CircuitBreaker 名称模式

CircuitBreaker 的名称遵循这种模式 <feignClientClassName>#<calledMethod>(<parameterTypes>)。例如,当调用一个带有 FooClient 接口的 @FeignClient,并且被调用的接口方法 bar 没有参数,那么 CircuitBreaker 的名称将是 FooClient#bar()。

自定义 CircuitBreaker 名称模式

从 2020.0.2 开始,CircuitBreaker 名称模式已经从 <feignClientName>_<calledMethod> 改变。使用 2020.0.4 中引入的 CircuitBreakerNameResolver,可以保留旧的命名模式。

import org.springframework.cloud.client.circuitbreaker.CircuitBreakerNameResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.lang.reflect.Method;@Configuration
public class FooConfiguration {@Beanpublic CircuitBreakerNameResolver circuitBreakerNameResolver() {return (String feignClientName, Target<?> target, Method method) -> feignClientName + "_" + method.getName();}
}

启用 Spring Cloud CircuitBreaker Group

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

spring:cloud:openfeign:circuitbreaker:group:enabled: true

使用配置属性配置 CircuitBreaker

在 Spring Cloud OpenFeign 中,可以通过配置属性来配置 CircuitBreaker。

定义 Feign 客户端

首先,定义一个 Feign 客户端接口。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;// 使用 @FeignClient 注解定义 Feign 客户端
@FeignClient(url = "http://localhost:8080")
public interface DemoClient {// 定义一个 GET 请求方法@GetMapping("/demo")String getDemo();
}

配置 CircuitBreaker

通过配置属性来配置 CircuitBreaker。

spring:cloud:openfeign:circuitbreaker:enabled: true  # 启用 CircuitBreakeralphanumeric-ids:enabled: true  # 启用字母数字 IDresilience4j:circuitbreaker:instances:DemoClientgetDemo:  # CircuitBreaker 实例名称minimumNumberOfCalls: 69  # 最小调用次数timelimiter:instances:DemoClientgetDemo:  # 时间限制器实例名称timeoutDuration: 10s  # 超时时间

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

spring:cloud:openfeign:circuitbreaker:enabled: truealphanumeric-ids:enabled: false  # 禁用字母数字 ID,使用旧的命名模式

Feign Spring Cloud CircuitBreaker Fallback

Spring Cloud CircuitBreaker 支持 fallback 的概念:一个默认的代码路径,在 circuit 打开或出现错误时执行。要为一个给定的 @FeignClient 启用 fallback,可以将 fallback 属性设置为实现 fallback 的类名。我们还需要将我们的实现声明为一个 Spring Bean。

定义 Feign 客户端

定义一个 Feign 客户端接口,并使用 @FeignClient 注解,设置 fallback 属性。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.stereotype.Component;@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();
}

定义 Fallback 类

定义一个 Fallback 类,实现 Feign 客户端接口,并在熔断器打开或出现错误时提供降级响应。

import org.springframework.stereotype.Component;
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;@Component
static class Fallback implements TestClient {@Overridepublic Hello getHello() {throw new NoFallbackAvailableException("Boom!", new RuntimeException());}@Overridepublic String getException() {return "Fixed response";}
}

使用 FallbackFactory 访问触发原因

如果需要访问使 fallback 触发的原因,可以使用 @FeignClient 里面的 fallbackFactory 属性。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.stereotype.Component;
import org.springframework.cloud.client.circuitbreaker.FallbackFactory;@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallbackFactory = TestClientFallbackFactory.class)
protected interface TestClient {@RequestMapping(method = RequestMethod.GET, value = "/hello")Hello getHello();@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")String getException();
}@Component
static class TestClientFallbackFactory implements FallbackFactory<TestClient> {@Overridepublic TestClient create(Throwable cause) {return new TestClient() {@Overridepublic Hello getHello() {System.out.println("Fallback cause: " + cause);throw new NoFallbackAvailableException("Boom!", cause);}@Overridepublic String getException() {System.out.println("Fallback cause: " + cause);return "Fixed response";}};}
}

Feign 和 @Primary

当使用 Feign 与 Spring Cloud CircuitBreaker fallback 时,ApplicationContext 中可能存在多个相同类型的 Bean。这将导致 @Autowired 不起作用,因为没有确切的一个 Bean,或一个被标记为 @Primary 的 Bean。为了解决这个问题,Spring Cloud OpenFeign 将所有 Feign 实例标记为 @Primary,因此 Spring Framework 将知道要注入哪个 Bean。在某些情况下,这可能是不可取的。要关闭这种行为,将 @FeignClient 的 primary 属性设置为 false。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@FeignClient(name = "test", url = "http://localhost:${server.port}/", primary = false)
public interface TestClient {@RequestMapping(method = RequestMethod.GET, value = "/hello")String getHello();
}

Feign 继承的支持

Feign 支持接口继承,这意味着你可以定义一个通用的接口,然后在多个 Feign 客户端中继承和重用这个接口。通过接口继承,可以减少代码重复,提高代码的可维护性和可读性。

定义通用接口

首先,定义一个通用的接口,包含一些通用的方法。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;public interface CommonApi {@GetMapping("/common/{id}")String getCommon(@PathVariable("id") Long id);
}

定义 Feign 客户端接口

定义一个 Feign 客户端接口,继承通用接口,并添加一些特定于该客户端的方法。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "demo-service", url = "http://localhost:8080")
public interface DemoClient extends CommonApi {@GetMapping("/demo/{id}")String getDemo(@PathVariable("id") Long id);
}

使用 Feign 客户端

在需要使用 Feign 客户端的地方,注入并调用接口方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {@Autowiredprivate DemoClient demoClient;@GetMapping("/demo/{id}")public String getDemo(@PathVariable Long id) {return demoClient.getDemo(id);}@GetMapping("/common/{id}")public String getCommon(@PathVariable Long id) {return demoClient.getCommon(id);}
}

Feign request/response 压缩

在微服务架构中,网络传输的数据量可能会非常大,尤其是在处理大量数据或频繁调用远程服务时。为了减少网络传输的开销,可以对 Feign 的请求和响应进行压缩。Feign 支持通过配置启用 Gzip 压缩,从而减少数据传输的大小,提高性能。

在配置文件中启用 Feign 的请求和响应压缩。

application.yml

spring:cloud:openfeign:compression:request:enabled: true  # 启用请求压缩mime-types: text/xml,application/xml,application/json  # 指定压缩的 MIME 类型min-request-size: 2048  # 指定最小请求大小(字节)response:enabled: true  # 启用响应压缩

application.properties

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
spring.cloud.openfeign.compression.response.enabled=true

Feign 日志

每个创建的 Feign 客户端都会创建一个 logger。默认情况下,logger 的名字是用于创建 Feign 客户端的接口的全类名称。Feign 的日志只响应 DEBUG 级别。

配置 Feign 日志

1、配置日志级别

在 application.yml 或 application.properties 中配置 Feign 客户端的日志级别。

application.yml

logging:level:project.user.UserClient: DEBUG

application.properties

logging.level.project.user.UserClient=DEBUG

配置 Logger.Level

可以为每个客户端配置 Logger.Level 对象,告诉 Feign 要记录多少内容。选择是:

  • NONE: 没日志(默认)。
  • BASIC: 只记录请求方法和 URL 以及响应状态代码和执行时间。
  • HEADERS: 记录基本信息以及请求和响应头。
  • FULL: 记录请求和响应的 header、正文和元数据。
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FeignConfig {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}

Micrometer 的支持

Spring Cloud OpenFeign 提供了对 Micrometer 的支持,使得 Feign 客户端的调用可以被 Micrometer 观察到。通过启用 Micrometer 支持,可以收集 Feign 客户端的调用指标,并将其集成到 Micrometer 的监控系统中。

配置 Micrometer 支持

在配置文件中启用 Micrometer 支持。

application.yml

spring:cloud:openfeign:micrometer:enabled: true  # 启用 Micrometer 支持

application.properties

spring.cloud.openfeign.micrometer.enabled=true

禁用 Micrometer 支持

可以通过以下两种方式禁用 Micrometer 支持:

  • 从 classpath 中排除 feign-micrometer。
  • 将 spring.cloud.openfeign.micrometer.enabled 设置为 false。

application.yml

spring:cloud:openfeign:micrometer:enabled: false  # 禁用 Micrometer 支持

application.properties

spring.cloud.openfeign.micrometer.enabled=false

自定义 MicrometerObservationCapability

可以通过注册你自己的 MicrometerObservationCapability Bean 来自定义 Micrometer 支持。

import io.micrometer.observation.ObservationRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.openfeign.MicrometerObservationCapability;@Configuration
public class FooConfiguration {@Beanpublic MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) {return new MicrometerObservationCapability(registry);}
}

使用 MicrometerCapability

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

import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.openfeign.MicrometerCapability;@Configuration
public class FooConfiguration {@Beanpublic MicrometerCapability micrometerCapability(MeterRegistry meterRegistry) {return new MicrometerCapability(meterRegistry);}
}

Feign 缓存

Spring Cloud OpenFeign 提供了对 Spring 缓存的支持,使得 Feign 客户端可以识别其接口上的 @Cache* 注解。通过启用缓存支持,可以减少对远程服务的调用次数,提高性能。

启用 Feign 缓存

在 Spring Boot 应用的主类上启用缓存。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients
@EnableCaching
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

定义一个 Feign 客户端接口,并使用 @Cacheable 注解。 

import org.springframework.cache.annotation.Cacheable;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "demo-service", url = "http://localhost:8080")
public interface DemoClient {@GetMapping("/demo/{filterParam}")@Cacheable(cacheNames = "demo-cache", key = "#keyParam")String demoEndpoint(String keyParam, @PathVariable String filterParam);
}

禁用 Feign 缓存

可以通过属性 spring.cloud.openfeign.cache.enabled=false 来禁用 Feign 缓存功能。

spring:cloud:openfeign:cache:enabled: false  # 禁用 Feign 缓存

Feign @QueryMap 的支持

Spring Cloud OpenFeign 提供了一个等价的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数注解为查询参数 map。通过使用 @SpringQueryMap 注解,可以更方便地将复杂对象转换为查询参数,而不需要手动拼接查询字符串。

1. 定义 POJO 类

首先,定义一个 POJO 类,用于表示查询参数。

public class QueryParams {private String param1;private String param2;// Getters and Setters
}

2. 定义 Feign 客户端接口

定义一个 Feign 客户端接口,并使用 @SpringQueryMap 注解将 POJO 或 Map 参数注解为查询参数 map。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;@FeignClient(name = "demo-service", url = "http://localhost:8080")
public interface DemoClient {@GetMapping("/demo")String getDemo(@SpringQueryMap QueryParams queryParams);
}

3. 使用 Feign 客户端

在需要使用 Feign 客户端的地方,注入并调用接口方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {@Autowiredprivate DemoClient demoClient;@GetMapping("/demo")public String getDemo() {QueryParams queryParams = new QueryParams();queryParams.setParam1("value1");queryParams.setParam2("value2");return demoClient.getDemo(queryParams);}
}

HATEOAS 的支持

Spring 提供了一些 API 来创建遵循 HATEOAS 原则的 REST 表示,如 Spring Hateoas 和 Spring Data REST。如果你的项目使用了 org.springframework.boot:spring-boot-starter-hateoas 或 org.springframework.boot:spring-boot-starter-data-rest starter,Feign HATEOAS 支持会被默认启用。

当HATEOAS支持被启用时,Feign 客户端被允许序列化和反序列化 HATEOAS 表示模型: EntityModel、 CollectionModel 和 PagedModel.。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "demo-service", url = "http://localhost:8080")
public interface DemoClient {@GetMapping("/demo/{id}")EntityModel<Demo> getDemo(@PathVariable("id") Long id);@GetMapping("/demos")CollectionModel<EntityModel<Demo>> getAllDemos();
}

OAuth2 的支持

Spring Cloud OpenFeign 提供了对 OAuth2 的支持,使得 Feign 客户端可以自动获取并附加 OAuth2 访问令牌到请求头中。通过启用 OAuth2 支持,可以简化与 OAuth2 保护的资源的交互。

 在配置文件中启用 OAuth2 支持,并指定 OAuth2 客户端的注册 ID。

spring:cloud:openfeign:oauth2:enabled: true  # 启用 OAuth2 支持clientRegistrationId: my-client-registration-id  # 指定 OAuth2 客户端的注册 ID

转换负载均衡的 HTTP 请求

在 Spring Cloud OpenFeign 中,你可以使用选定的 ServiceInstance 来转换负载均衡的 HTTP 请求。为了实现这一点,你需要实现和定义 LoadBalancerFeignRequestTransformer,该接口允许你在请求发送到目标服务之前对其进行转换。

实现 LoadBalancerFeignRequestTransformer

1. 实现 LoadBalancerFeignRequestTransformer

首先,实现 LoadBalancerFeignRequestTransformer 接口,并在 transformRequest 方法中定义请求转换逻辑。

 

import feign.Request;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerFeignRequestTransformer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;@Configuration
public class FeignConfig {// 定义一个 LoadBalancerFeignRequestTransformer Bean@Beanpublic LoadBalancerFeignRequestTransformer transformer() {return new LoadBalancerFeignRequestTransformer() {// 实现 transformRequest 方法,定义请求转换逻辑@Overridepublic Request transformRequest(Request request, ServiceInstance instance) {// 创建一个新的请求头 Map,并复制原始请求的请求头Map<String, Collection<String>> headers = new HashMap<>(request.headers());// 添加自定义请求头,包含服务 IDheaders.put("X-ServiceId", Collections.singletonList(instance.getServiceId()));// 添加自定义请求头,包含实例 IDheaders.put("X-InstanceId", Collections.singletonList(instance.getInstanceId()));// 创建并返回一个新的 Request 对象,包含转换后的请求头return Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(),request.requestTemplate());}};}
}

2. 配置 Feign 客户端

在 Feign 客户端配置中,启用负载均衡并使用自定义的 LoadBalancerFeignRequestTransformer。 

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;// 定义一个 Feign 客户端接口,启用负载均衡
@FeignClient(name = "demo-service")
public interface DemoClient {// 定义一个 GET 请求方法@GetMapping("/demo/{id}")String getDemo(@PathVariable("id") Long id);
}

参考文章

常见的应用属性

Spring Cloud OpenFeign 中文文档

相关文章:

OpenFeign使用详解

什么是OpenFeign&#xff1f; OpenFeign 是一个声明式的 HTTP 客户端&#xff0c;旨在简化微服务架构中不同服务之间的 HTTP 调用。它通过集成 Ribbon 实现了客户端负载均衡&#xff0c;并且能够与 Eureka、Consul 等服务发现组件无缝对接。使用 OpenFeign&#xff0c;开发者只…...

CSS clip-path 属性的使用

今天记录一个css属性clip-path&#xff0c;首先介绍下这个属性。 clip-path 是CSS中的一个神奇属性&#xff0c;它能够让你像魔术师一样&#xff0c;对网页元素施展“裁剪魔法”——只展示元素的一部分&#xff0c;隐藏其余部分。想象一下&#xff0c;不用依赖图片编辑软件&am…...

PHP 函数

PHP 函数 PHP&#xff08;超文本预处理器&#xff09;是一种广泛使用的开源服务器端脚本语言&#xff0c;特别适合于网页开发。在PHP中&#xff0c;函数是一段可重复使用的代码&#xff0c;用于执行特定任务。它们是PHP编程的核心组成部分&#xff0c;有助于模块化代码&#x…...

NCEloss与InfoNCEloss的区别

NCE Loss&#xff08;Noise Contrastive Estimation Loss&#xff09;和 InfoNCE Loss 是两种常用的损失函数&#xff0c;主要应用在对比学习和自监督学习任务中。它们的区别在于应用场景和具体实现细节。下面是对两者的详细比较&#xff1a; 1. NCE Loss&#xff08;Noise Co…...

高通Android 12 push framework.jar和service.jar

1、Android framework.jar和service.jar替换注意事项 2、单编 adb push service.jar脚本 如下 adb root adb disable-verity adb remountadb push services.jar system/framework adb push services.jar.prof system/framework adb push oat/arm64/services.art /system/fram…...

HTTPS证书配置

NGINX、SSl配置 修改conf目录下NGINX中的crt和key文件 单点配置SSL 需要的文件和配置信息 证书和keytool.exe(使用jdk1.8的)工具要在同一个目录下 gxszy.qhxzhny.top.pfx&#xff08;证书&#xff09; keystorePass.txt&#xff08;密码&#xff09; 使用JDK自带的keyto…...

Image matting入门

概念 matting就是扣图&#xff0c;本质是预测前景与背景&#xff0c;将前景扣出来。主要应用于影视行业&#xff0c;如拍电影绿幕扣图。和图像分割的区别在于多一个模糊地带&#xff0c;非01分类&#xff0c;变成了预测alpha通道。前景F&#xff0c;背景B&#xff0c;图像I可以…...

基于安全风险预测的自动驾驶自适应巡航控制优化

摘要 :从周边车辆运动学状态参数和道路设施条件参数中提取场景特征指标和安全风险度量指标,采用极端梯度提升模型(XGboost )和长短时记忆模型( LSTM )进行安全风险预测,由此提出基于安全风险预测的自动驾驶自适应巡航控制(ACC )优化方法,并选取碰撞发生概率、速度平均…...

Docker Compose 搭建 Redis 哨兵集群模式搭建详解(1主2从+3哨兵)(包含主从复制的搭建) (保证一遍学会)

目录 哨兵的作用和工作原理 服务状态监控 选举新的 master 如何实现故障转移 搭建哨兵集群 哨兵的作用和工作原理 Redis 提供了哨兵 (Sentinel) 机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下 监控&#xff1a;Sentinel 会不断检查你的 master 和 slave 是否按…...

Oracle 单机和集群环境部署教程

目录 一、Oracle 单机环境部署1. 环境准备2. 安装 Oracle Database2.1 下载 Oracle Database2.2 创建 Oracle 用户和组2.3 配置内核参数和系统限制2.4 解压和安装2.5 配置监听程序2.6 创建数据库 3. 单机部署注意事项 二、Oracle 集群环境部署 (Oracle RAC)1. 环境准备2. 安装 …...

springboot 整合酷狗获取MV视频最高画质(使用自己账户)

在此声明&#xff0c;本内容仅供个人学习、研究或娱乐之用&#xff0c;严禁任何形式的商业用途。若您发现本内容被用于商业目的&#xff0c;请立即删除&#xff0c;及时与小编联系&#xff0c;我们将删除原代码。 请根据上一篇文章使用该代码&#xff1a;SpringBoot 整合酷狗获…...

数字孪生平台,助力制造设备迈入超感知与智控新时代!

痛点剖析 当前&#xff0c;制造业面临系统分散导致的数据孤岛问题&#xff0c;严重阻碍了有效监管与统计分析&#xff1b;同时&#xff0c;设备多样化且兼容性不足&#xff0c;增加了管理难度&#xff1b;台账记录方式混乱&#xff0c;工单审批流程繁琐且效率低下&#xff1b;…...

音视频入门基础:AAC专题(10)——FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…...

pycirclize python包画circos环形图

pycirclize python包画circos环形图 很多小伙伴都有画环形图的需求&#xff0c;网上也有很多画环形图的教程&#xff0c;讲解circos软件和circlize R包的比较多&#xff0c;本文介绍一款python包:pyCirclize。适合喜欢python且希望更灵活作图的小伙伴。 pyCirclize包实际上也…...

Redis Sorted Set 跳表的实现原理和分析

跳表&#xff08;Skip List&#xff09;是一种随机化的数据结构&#xff0c;基于有序链表&#xff0c;通过在链表上增加多级索引来提高数据的查找效率。它是由 William Pugh 在 1990 年提出的。 为什么 Redis 中的 Sorted Set 使用跳跃表 Redis 的有序集合&#xff08;Sorted …...

新手教学系列——在MySQL分表中批量调整表结构的实践与优化

在当今的互联网业务中,随着数据量的不断增长,单个数据库的处理能力往往难以满足高并发、高性能的要求。因此,分库分表已经成为解决数据库扩展性问题的主流方案之一。然而,分表虽然能有效提升数据库的读写性能,但也带来了一个新的挑战:当业务需求变化时,需要对大量分表进…...

解决事务提交延迟问题:Spring中的事务绑定事件监听机制解析

目录 一、背景二、事务绑定事件介绍三、事务绑定事件原理四、结语 一、背景 实际工作中碰到一个场景&#xff0c;现存系统有10w张卡需要进行换卡&#xff0c;简单来说就是为用户生成一张新卡&#xff0c;批量换卡申请需要进行审核&#xff0c;审核通过后异步进行处理。 为什么…...

Python 异步编程的秘密武器:Asyncio

python编程中&#xff0c;异步编程是一个重要概念。它允许我们在等待某些操作&#xff08;如网络请求或文件读写&#xff09;时&#xff0c;不阻塞程序的其他部分运行。 在 Python 中&#xff0c;asyncio 是实现异步编程的强大工具。今天&#xff0c;我们将一同探索 asyncio 的…...

10年计算机考研408-计算机网络

【题33】下列选项中&#xff0c;不属于网络体系结构所描述的内容是&#xff08;&#xff09; A.网络的层次 B.每一层使用的协议 C.协议的内部实现细节 D.每一层必须完成的功能 解析&#xff1a; 本题考查的是网络体系结构相关的概念。 图1描述了网络的7层架构以及每一层所要完成…...

深信服校招面试总结

许久没有更新博客&#xff0c;这两个月里发生的事情有些多。最近稍微稳定下来了&#xff0c;应该可以重新开始吧。 背景 首先感觉自己的笔试做的还行&#xff0c;除了第三个编程题没做出来&#xff0c;其他的应该都做出来了。当时忘记并查集的路径压缩怎么写了&#xff0c;加上…...

【LeetCode热题100】模拟

这篇博客记录了模拟相关的题目&#xff0c;也就是按照题目的描述写代码&#xff0c;很锻炼代码实现能力&#xff0c;包括了替换所有的问号、Z字形变换、外观数列、数青蛙4道题。 class Solution { public:string modifyString(string s) {int n s.size();for(int i 0 ; i <…...

如何在Chrome最新浏览器中调用ActiveX控件?

小编最近登陆工商银行网上银行&#xff0c;发现工商银行的个人网银网页&#xff0c;由于使用了ActiveX安全控件&#xff0c;导致不能用高版本Chrome浏览器打开&#xff0c;目前只有使用IE或基于IE内核的浏览器才能正常登录网上银行&#xff0c;而IE已经彻底停止更新了&#xff…...

一款好用的远程连接工具:MobaXterm

在日常工作中&#xff0c;作为开发者或运维人员&#xff0c;你是否经常需要远程连接服务器进行调试和管理&#xff1f;传统的SSH工具常常不够灵活&#xff0c;操作繁琐&#xff0c;无法满足日益复杂的工作需求。而MobaXterm的出现&#xff0c;带来了远程连接工具的全新体验。它…...

Spring Boot使用配置方式整合MyBatis

文章目录 一、实战目标二、步骤概览1. 创建部门映射器接口2. 创建映射器配置文件3. 配置全局映射器4. 测试映射器接口 三、详细步骤1、创建部门映射器接口2、创建映射器配置文件3、配置全局映射器4、测试映射器接口 四、结语 一、实战目标 在本实战课程中&#xff0c;我们将学…...

HarmonyOS第一课-应用程序框架基础习题答案

声明&#xff1a;本题库为最新的HarmonyOS第一课的学习题库&#xff0c;仅供参考学习&#xff01; 一、判断题 1. 在基于Stage模型开发的应用项目中都存在一个app.json5配置文件、以及一个或多个module.json5配置文件。&#xff08;正确&#xff09; 正确(True) 错误(False) -…...

滚雪球学SpringCloud[10.2讲]:微服务项目的性能优化与调优

全文目录: 前言性能优化与调优概述性能优化的核心目标常见的性能瓶颈来源 性能瓶颈分析与调优策略1. 服务间通信优化优化策略&#xff1a; 2. 数据库优化优化策略&#xff1a; 3. 线程池优化优化策略&#xff1a; 4. 缓存优化优化策略&#xff1a; 常见问题的排查与解决1. 慢查…...

EasyExcel将数据库里面的数据生成excel文件

EasyExcel官方文档 1.在model模块导入依赖 <!-- 生成报表--> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version> </dependency> 2.修饰实体类 package…...

【YOLO学习】YOLOv1详解

文章目录 1. 概述2. 算法流程3. 网络结构4. 损失函数 1. 概述 1. YOLO 的全称是 You Only Look Once: Unified, Real-Time Object Detection。YOLOv1 的核心思想就是利用整张图作为网络的输入&#xff0c;直接在输出层回归 bounding box 的位置和 bounding box 所属的类别。简单…...

HarmonyOS应用开发(组件库)--组件模块化开发、工具包、设计模式(持续更新)

致力于&#xff0c;UI开发拿来即用&#xff0c;提高开发效率 常量格式枚举enum格式正则表达式...手机号校验...邮箱校验 文件判断文件是否存在 网络下载下载图片从沙箱中图片转为Base64格式从资源文件中读取图片转Base64 组件输入框...矩形输入框...输入框堆叠效果&#xff08;…...

python测试开发---前后端交互Axios

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;常用于浏览器和 Node.js 中发送 HTTP 请求。它封装了 XMLHttpRequest 和 Node.js 的 http 模块&#xff0c;使得处理网络请求更加简单和直观&#xff0c;尤其适合处理异步请求。以下是 Axios 的基础概念和使用方法&#xf…...