Intro to Feign – 伪装介绍

最后修改: 2016年 9月 25日


1. Overview


In this tutorial, we’ll introduce Feign — a declarative HTTP client developed by Netflix.


Feign aims at simplifying HTTP API clients. Simply put, the developer needs only to declare and annotate an interface while the actual implementation is provisioned at runtime.

Feign的目标是简化HTTP API客户端。简单地说,开发者只需要声明和注解一个接口,而实际的实现是在运行时提供的。

2. Example


Throughout this tutorial, we’ll be using an example bookstore application that exposes the REST API endpoint.

在本教程中,我们将使用一个示例书店应用程序,它暴露了REST API端点。

We can easily clone the project and run it locally:


mvn install spring-boot:run

3. Setup


First, let’s add the needed dependencies:



Besides the feign-core dependency (which is also pulled in), we’ll use a few plugins, especially feign-okhttp for internally using Square’s OkHttp client to make requests, feign-gson for using Google’s GSON as JSON processor and feign-slf4j for using the Simple Logging Facade to log requests.

除了feign-core依赖(也被拉入),我们将使用一些插件,特别是feign-okhttp,用于在内部使用Square的OkHttp客户端来发出请求,feign-gson用于使用 Google 的 GSON 作为 JSON 处理器,以及feign-slf4j用于使用Simple Logging Facade来记录请求。

To actually get some log output, we’ll need our favorite SLF4J-supported logger implementation on the classpath.


Before we proceed to create our client interface, first we’ll set up a Book model for holding the data:


public class Book {
    private String isbn;
    private String author;
    private String title;
    private String synopsis;
    private String language;

    // standard constructor, getters and setters

NOTE: At least a “no arguments constructor” is needed by a JSON processor.

注意:一个JSON处理器至少需要一个 “无参数构造函数”。

In fact, our REST provider is a hypermedia-driven API, so we’ll additionally need a simple wrapper class:


public class BookResource {
    private Book book;

    // standard constructor, getters and setters

Note: We’ll keep the BookResource simple because our sample Feign client doesn’t benefit from hypermedia features!


4. Server Side


To understand how to define a Feign client, we’ll first look into some of the methods and responses supported by our REST provider.


Let’s try it out with a simple curl shell command to list all the books.

让我们用一个简单的curl shell命令来试试,列出所有的书。

We need to remember to prefix all the calls with /api, which is the application’s servlet-context:


curl http://localhost:8081/api/books

As a result, we’ll get a complete book repository represented as JSON:


    "book": {
      "isbn": "1447264533",
      "author": "Margaret Mitchell",
      "title": "Gone with the Wind",
      "synopsis": null,
      "language": null
    "links": [
        "rel": "self",
        "href": "http://localhost:8081/api/books/1447264533"


    "book": {
      "isbn": "0451524934",
      "author": "George Orwell",
      "title": "1984",
      "synopsis": null,
      "language": null
    "links": [
        "rel": "self",
        "href": "http://localhost:8081/api/books/0451524934"

We can also query an individual Book resource, by appending the ISBN to a get request:


curl http://localhost:8081/api/books/1447264533

5. Feign Client


Finally, let’s define our Feign client.


We’ll use the @RequestLine annotation to specify the HTTP verb and a path part as an argument.


The parameters will be modeled using the @Param annotation:


public interface BookClient {
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("isbn") String isbn);

    List<BookResource> findAll();

    @Headers("Content-Type: application/json")
    void create(Book book);

NOTE: Feign clients can be used to consume text-based HTTP APIs only, which means that they cannot handle binary data, e.g., file uploads or downloads.

注意:Feign客户端只能用于消费基于文本的HTTP API,这意味着它们不能处理二进制数据,例如,文件上传或下载。

That’s all! Now we’ll use the Feign.builder() to configure our interface-based client.


The actual implementation will be provisioned at runtime:


BookClient bookClient = Feign.builder()
  .client(new OkHttpClient())
  .encoder(new GsonEncoder())
  .decoder(new GsonDecoder())
  .logger(new Slf4jLogger(BookClient.class))
  .target(BookClient.class, "http://localhost:8081/api/books");

Feign supports various plugins such as JSON/XML encoders and decoders or an underlying HTTP client for making the requests.


6. Unit Test


Let’s create three test cases to test our client.


Note that we use static imports for org.hamcrest.CoreMatchers.* and org.junit.Assert.*:


public void givenBookClient_shouldRunSuccessfully() throws Exception {
   List<Book> books = bookClient.findAll().stream()

   assertTrue(books.size() > 2);

public void givenBookClient_shouldFindOneBook() throws Exception {
    Book book = bookClient.findByIsbn("0151072558").getBook();
    assertThat(book.getAuthor(), containsString("Orwell"));

public void givenBookClient_shouldPostBook() throws Exception {
    String isbn = UUID.randomUUID().toString();
    Book book = new Book(isbn, "Me", "It's me!", null, null);
    book = bookClient.findByIsbn(isbn).getBook();

    assertThat(book.getAuthor(), is("Me"));

7. Further Reading


If we need some kind of a fallback in case of the service unavailability, we could add HystrixFeign to the classpath and build our client with HystrixFeign.builder().


Check out this dedicated tutorial series to learn more about Hystrix.


Additionally, if we’d like to integrate Spring Cloud Netflix Hystrix with Feign, there’s a dedicated article over here.

此外,如果我们想将Spring Cloud Netflix Hystrix与Feign集成,在这里有一篇专门的文章。

Moreover, it’s also possible to add client-side load balancing and/or service discovery to our client.


We could achieve this by adding Ribbon to our classpath and using the builder:


BookClient bookClient = Feign.builder()
  .target(BookClient.class, "http://localhost:8081/api/books");

For service discovery, we have to build up our service with Spring Cloud Netflix Eureka enabled. Then we simply integrate with Spring Cloud Netflix Feign. As a result, we get Ribbon load balancing for free. More about this can be found here.

对于服务发现,我们必须在启用Spring Cloud Netflix Eureka后建立我们的服务。然后我们简单地与Spring Cloud Netflix Feign集成。因此,我们可以免费获得Ribbon负载均衡。关于这一点的更多信息可在此处找到。

8. Conclusion


In this article, we’ve explained how to build a declarative HTTP client using Feign to consume text-based APIs.


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