Introduction to Spring Cloud OpenFeign – Spring Cloud OpenFeign简介

最后修改: 2019年 3月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’re going to describe Spring Cloud OpenFeign — a declarative REST client for Spring Boot apps.

在本教程中,我们将介绍Spring Cloud OpenFeign–Spring Boot应用程序的声明式REST客户端。

Feign makes writing web service clients easier with pluggable annotation support, which includes Feign annotations and JAX-RS annotations.

Feign通过可插拔的注解支持,包括Feign注解和JAX-RS注解,使编写Web服务客户端更加容易。

Also, Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters as used in Spring Web.

此外,Spring Cloud增加了对Spring MVC 注释的支持,并支持使用与 Spring Web 中使用的相同的HttpMessageConverters

One great thing about using Feign is that we don’t have to write any code for calling the service, other than an interface definition.

使用Feign的一个好处是,除了一个接口定义外,我们不需要写任何调用服务的代码。

2. Dependencies

2.依赖性

First, we’ll start by creating a Spring Boot web project and adding the spring-cloud-starter-openfeign dependency to our pom.xml file:

首先,我们先创建一个Spring Boot网络项目,并将spring-cloud-starter-openfeign依赖关系添加到我们的pom.xml文件。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Also, we’ll need to add the spring-cloud-dependencies:

此外,我们还需要添加 spring-cloud-dependencies

 <dependencyManagement>
     <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

We can find the latest versions of spring-cloud-starter-openfeign and spring-cloud-dependencies on Maven Central.

我们可以在Maven中心找到spring-cloud-starter-openfeignspring-cloud-dependencies的最新版本。

3. Feign Client

3.假扮客户

Next, we need to add @EnableFeignClients to our main class:

接下来,我们需要将@EnableFeignClients加入我们的主类。

@SpringBootApplication
@EnableFeignClients
public class ExampleApplication {

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

With this annotation, we enable component scanning for interfaces that declare they are Feign clients.

有了这个注解,我们就可以对那些声明自己是Feign客户的接口进行组件扫描。

Then we declare a Feign client using the @FeignClient annotation:

然后我们使用@FeignClientannotation声明一个Feign客户端。

@FeignClient(value = "jplaceholder", url = "https://jsonplaceholder.typicode.com/")
public interface JSONPlaceHolderClient {

    @RequestMapping(method = RequestMethod.GET, value = "/posts")
    List<Post> getPosts();

    @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
    Post getPostById(@PathVariable("postId") Long postId);
}

In this example, we’ve configured a client to read from the JSONPlaceholder APIs.

在这个例子中,我们已经配置了一个客户端,以便从JSONPlaceholder APIs中读取。

The value argument passed in the @FeignClient annotation is a mandatory, arbitrary client name, while with the url argument, we specify the API base URL.

@FeignClient注释中传递的value参数是一个强制性的、任意的客户端名称,而通过url参数,我们指定了API基础URL。

Furthermore, since this interface is a Feign client, we can use the Spring Web annotations to declare the APIs that we want to reach out to.

此外,由于这个接口是一个Feign客户端,我们可以使用Spring Web注解来声明我们要接触的API。

4. Configuration

4.配置

Now, it’s very important to understand that each Feign client is composed of a set of customizable components.

现在,理解以下一点非常重要:每个Feign客户端是由一组可定制的组件组成的。

Spring Cloud creates a new default set on demand for each named client using the FeignClientsConfiguration class that we can customize as explained in the next section.

Spring Cloud使用FeignClientsConfiguration类为每个命名的客户按需创建一个新的默认集,我们可以按照下一节的解释进行定制。

The above class contains these beans:

上面的类包含这些Bean。

  • Decoder – ResponseEntityDecoder, which wraps SpringDecoder, used to decode the Response
  • Encoder – SpringEncoder is used to encode the RequestBody.
  • Logger – Slf4jLogger is the default logger used by Feign.
  • Contract – SpringMvcContract, which provides annotation processing
  • Feign-Builder – HystrixFeign.Builder is used to construct the components.
  • Client – LoadBalancerFeignClient or default Feign client

4.1. Custom Beans Configuration

4.1.自定义Bean配置

If we want to customize one or more of these beans, we can override them by creating a Configuration class, which we then add to the FeignClient annotation:

如果我们想定制这些Bean中的一个或多个,我们可以通过创建一个Configuration类来覆盖它们,然后将其添加到FeignClient注释中。

@FeignClient(value = "jplaceholder",
  url = "https://jsonplaceholder.typicode.com/",
  configuration = MyClientConfiguration.class)
public class MyClientConfiguration {

    @Bean
    public OkHttpClient client() {
        return new OkHttpClient();
    }
}

In this example, we tell Feign to use OkHttpClient instead of the default one to support HTTP/2.

在这个例子中,我们告诉Feign使用OkHttpClient而不是默认的,以支持HTTP/2。

Feign supports multiple clients for different use cases, including the ApacheHttpClient, which sends more headers with the request, for example, Content-Length, which some servers expect.

Feign为不同的使用情况支持多个客户端,包括ApacheHttpClient,它在请求中发送更多的头信息,例如,Content-Length,这是一些服务器期望的。

To use these clients, let’s not forget to add the required dependencies to our pom.xml file:

为了使用这些客户端,我们不要忘记在我们的pom.xml文件中添加所需的依赖性。

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

We can find the latest versions of feign-okhttp and feign-httpclient on Maven Central.

我们可以在Maven中心找到feign-okhttpfeign-httpclient的最新版本。

4.2. Configuration Using Properties

4.2.使用属性进行配置

Rather than use a Configuration class, we can use application properties to configure Feign clients, as shown in this application.yaml example:

与其使用Configuration类,我们可以使用应用程序属性来配置Feign客户端,如这个application.yaml例子中所示。

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic

With this configuration, we’re setting the timeouts to five seconds and the logger level to basic for each declared client in the application.

通过这个配置,我们为应用程序中每个已声明的客户端设置超时为5秒,日志记录器级别为basic

Finally, we can create the configuration with default as the client name to configure all @FeignClient objects, or we can declare the feign client name for a configuration:

最后,我们可以用default作为客户端名称创建配置,以配置所有@FeignClient对象,或者我们可以为一个配置声明feign客户端名称。

feign:
  client:
    config:
      jplaceholder:

If we have both Configuration bean and configuration properties, configuration properties will override Configuration bean values.

如果我们同时拥有Configurationbean和配置属性,配置属性将覆盖Configurationbean值。

5. Interceptors

5.拦截器

Adding interceptors is another useful feature provided by Feign.

添加拦截器是Feign提供的另一个有用的功能。

The interceptors can perform a variety of implicit tasks, from authentication to logging, for every HTTP request/response.

拦截器可以为每个HTTP请求/响应执行各种隐性任务,从认证到记录。

In this section, we’ll implement our own interceptor, as well as use the one provided by the Spring Cloud OpenFeign out-of-the-box. Both will add a basic authentication header to each request.

在本节中,我们将实现我们自己的拦截器,以及使用Spring Cloud OpenFeign提供的开箱即用的拦截器。两者都将为每个请求添加一个基本认证头。

5.1. Implementing RequestInterceptor

5.1.实现RequestInterceptor

Let’s implement our custom request interceptor:

让我们来实现我们的自定义请求拦截器。

@Bean
public RequestInterceptor requestInterceptor() {
  return requestTemplate -> {
      requestTemplate.header("user", username);
      requestTemplate.header("password", password);
      requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
  };
}

Also, to add the interceptor to the request chain, we just need to add this bean to our Configuration class or, as we saw previously, declare it in the properties file:

另外,为了将拦截器添加到请求链中,我们只需要将这个bean添加到我们的Configuration类中,或者像我们之前看到的那样,在属性文件中声明它。

feign:
  client:
    config:
      default:
        requestInterceptors:
          com.baeldung.cloud.openfeign.JSONPlaceHolderInterceptor

5.2. Using BasicAuthRequestInterceptor

5.2.使用BasicAuthRequestInterceptor

Alternatively, we can use the BasicAuthRequestInterceptor class that the Spring Cloud OpenFeign provides:

另外,我们可以使用Spring Cloud OpenFeign提供的BasicAuthRequestInterceptor类。

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

It’s simple as that. Now all the requests will contain the basic authentication header.

就这么简单。现在所有的请求都将包含基本认证头。

6. Hystrix Support

6.Hystrix支持

Feign supports Hystrix, so if we have enabled it, we can implement the fallback pattern.

Feign支持Hystrix,所以如果我们启用了它,我们可以实现回退模式。

With the fallback pattern, when a remote service call fails, rather than generating an exception, the service consumer will execute an alternative code path to try to carry out the action through another means.

通过回退模式,当远程服务调用失败时,服务消费者将执行一个替代的代码路径,以尝试通过其他方式执行该动作,而不是产生一个异常。

To achieve the goal, we need to enable Hystrix by adding feign.hystrix.enabled=true in the properties file.

为了实现这一目标,我们需要在属性文件中添加feign.hystrix.enabled=true,以启用Hystrix。

This allows us to implement fallback methods that are called when the service fails:

这使我们能够实现当服务失败时被调用的回退方法。

@Component
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {

    @Override
    public List<Post> getPosts() {
        return Collections.emptyList();
    }

    @Override
    public Post getPostById(Long postId) {
        return null;
    }
}

To let Feign know that fallback methods have been provided, we also need to set our fallback class in the @FeignClient annotation:

为了让Feign知道已经提供了回退方法,我们还需要在@FeignClient注解中设置我们的回退类。

@FeignClient(value = "jplaceholder",
  url = "https://jsonplaceholder.typicode.com/",
  fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
    // APIs
}

7. Logging

7.登录

For each Feign client, a logger is created by default.

对于每个Feign客户端,默认情况下都会创建一个记录器。

To enable logging, we should declare it in the application.properties file using the package name of the client interfaces:

为了启用日志,我们应该在application.properties文件中使用客户接口的包名声明它。

logging.level.com.baeldung.cloud.openfeign.client: DEBUG

Or, if we want to enable logging only for one particular client in a package, we can use the full class name:

或者,如果我们想在一个包中只为一个特定的客户端启用日志,我们可以使用全类名称。

logging.level.com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient: DEBUG

Note that Feign logging responds only to the DEBUG level.

注意,Feign日志只对DEBUG级别做出响应。

The Logger.Level that we may configure per client indicates how much to log:

我们可以为每个客户配置的 Logger.Level表明要记录多少内容。

public class ClientConfiguration {
    
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
}

There are four logging levels to choose from:

有四个记录级别可供选择。

  • NONE – no logging, which is the default
  • BASIC – log only the request method, URL and response status
  • HEADERS – log the basic information together with request and response headers
  • FULL – log the body, headers and metadata for both request and response

8. Error Handling

8.错误处理

Feign’s default error handler, ErrorDecoder.default, always throws a FeignException.

Feign的默认错误处理程序,ErrorDecoder.default,总是抛出一个FeignException

Now, this behavior isn’t always the most useful. So, to customize the Exception thrown, we can use a CustomErrorDecoder:

现在,这种行为并不总是最有用的。所以,为了自定义抛出的异常,我们可以使用CustomErrorDecoder

public class CustomErrorDecoder implements ErrorDecoder {
    @Override
    public Exception decode(String methodKey, Response response) {

        switch (response.status()){
            case 400:
                return new BadRequestException();
            case 404:
                return new NotFoundException();
            default:
                return new Exception("Generic error");
        }
    }
}

Then, as we’ve done previously, we have to replace the default ErrorDecoder by adding a bean to the Configuration class:

然后,正如我们之前所做的,我们必须通过向Configuration类添加一个bean来替换默认的ErrorDecoder

public class ClientConfiguration {

    @Bean
    public ErrorDecoder errorDecoder() {
        return new CustomErrorDecoder();
    }
}

9. Conclusion

9.结论

In this article, we discussed Spring Cloud OpenFeign and its implementation in a simple sample application.

在这篇文章中,我们讨论了Spring Cloud OpenFeign以及它在一个简单的示例应用程序中的实现。

We’ve also seen how to configure a client, add interceptors to our requests and handle errors using Hystrix and ErrorDecoder.

我们还看到了如何配置客户端,为我们的请求添加拦截器,并使用HystrixErrorDecoder处理错误。

As usual, all code samples shown in this tutorial are available over on GitHub.

像往常一样,本教程中显示的所有代码样本都可以在GitHub上找到