1. Обзор
В этом уроке мы представим Feign – декларативный HTTP-клиент, разработанный Netflix.
Притворство направлено на упрощение клиентов HTTP API. Проще говоря, разработчику нужно только объявить и аннотировать интерфейс, в то время как фактическая реализация подготовлена во время выполнения.
2. Пример
На протяжении всего этого урока мы будем использовать пример приложения bookstore , которое предоставляет конечную точку REST API.
Мы можем легко клонировать проект и запускать его локально:
mvn install spring-boot:run
3. Настройка
Во-первых, давайте добавим необходимые зависимости:
io.github.openfeign feign-okhttp 10.11 io.github.openfeign feign-gson 10.11 io.github.openfeign feign-slf4j 10.11
Помимо зависимости feign-core (которая также включена), мы будем использовать несколько плагинов, особенно: feign-okhttp для внутреннего использования клиента Square OkHttp для выполнения запросов, feign-gson для использования GSON Google в качестве процессора JSON и feign-slf4j для использования фасада Simple Logging для регистрации запросов.
Чтобы действительно получить некоторые выходные данные журнала, нам понадобится наша любимая реализация регистратора с поддержкой SLF4J в пути к классам.
Прежде чем мы приступим к созданию нашего клиентского интерфейса, сначала мы настроим модель Book для хранения данных:
public class Book { private String isbn; private String author; private String title; private String synopsis; private String language; // standard constructor, getters and setters }
ПРИМЕЧАНИЕ: По крайней мере, “конструктор без аргументов” необходим процессору JSON.
На самом деле, наш поставщик REST-это управляемый гипермедиа API , , поэтому нам дополнительно понадобится простой класс-оболочка:
public class BookResource { private Book book; // standard constructor, getters and setters }
Примечание: Мы ‘ сохраним Книжный ресурс просто потому, что наш пример притворного клиента не использует возможности гипермедиа!
4. Серверная сторона
Чтобы понять, как определить Feignclient, мы сначала рассмотрим некоторые методы и ответы, поддерживаемые нашим поставщиком REST.
Давайте попробуем это с помощью простой команды оболочки curl, чтобы перечислить все книги. Нам нужно не забыть префиксировать все вызовы с помощью /api , который является контекстом сервлета приложения:
curl http://localhost:8081/api/books
В результате мы получим полное хранилище книг, представленное в виде 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" } ] } ]
Мы также можем запросить отдельные Книги ресурсы, добавив ISBN к запросу get:
curl http://localhost:8081/api/books/1447264533
5. Симулируйте Клиента
Наконец, давайте определим нашего Притворного клиента.
Мы будем использовать аннотацию @RequestLine , чтобы указать глагол HTTP и часть пути в качестве аргумента. Параметры будут смоделированы с помощью аннотации @Param :
public interface BookClient { @RequestLine("GET /{isbn}") BookResource findByIsbn(@Param("isbn") String isbn); @RequestLine("GET") ListfindAll(); @RequestLine("POST") @Headers("Content-Type: application/json") void create(Book book); }
ПРИМЕЧАНИЕ: Притворные клиенты могут использоваться только для использования текстовых HTTP-API, что означает, что они не могут обрабатывать двоичные данные, например, загрузку файлов или загрузку.
Вот и все! Теперь мы будем использовать Feign.builder() для настройки нашего клиента на основе интерфейса. Фактическая реализация будет подготовлена во время выполнения:
BookClient bookClient = Feign.builder() .client(new OkHttpClient()) .encoder(new GsonEncoder()) .decoder(new GsonDecoder()) .logger(new Slf4jLogger(BookClient.class)) .logLevel(Logger.Level.FULL) .target(BookClient.class, "http://localhost:8081/api/books");
Feign поддерживает различные плагины, такие как кодеры и декодеры JSON/XML или базовый HTTP-клиент для выполнения запросов.
6. Модульный тест
Давайте создадим три тестовых случая для тестирования нашего клиента. Обратите внимание, что мы используем статический импорт для org.hamcrest.CoreMatchers.* и org.junit.Утверждение.* :
@Test public void givenBookClient_shouldRunSuccessfully() throws Exception { Listbooks = bookClient.findAll().stream() .map(BookResource::getBook) .collect(Collectors.toList()); assertTrue(books.size() > 2); } @Test public void givenBookClient_shouldFindOneBook() throws Exception { Book book = bookClient.findByIsbn("0151072558").getBook(); assertThat(book.getAuthor(), containsString("Orwell")); } @Test public void givenBookClient_shouldPostBook() throws Exception { String isbn = UUID.randomUUID().toString(); Book book = new Book(isbn, "Me", "It's me!", null, null); bookClient.create(book); book = bookClient.findByIsbn(isbn).getBook(); assertThat(book.getAuthor(), is("Me")); }
7. Дальнейшее Чтение
Если нам нужен какой-то запасной вариант в случае недоступности службы, мы могли бы добавить HystrixFeign в путь к классу и построить наш клиент с помощью HystrixFeign.builder() .
Ознакомьтесь с этой специальной серией учебников, чтобы узнать больше о Hystrix.
Кроме того, если мы хотим интегрировать Spring Cloud Netflix Hystrix с Feign, здесь есть специальная статья .
Кроме того, к нашему клиенту также можно добавить балансировку нагрузки на стороне клиента и/или обнаружение служб.
Мы могли бы достичь этого, добавив Ribbon в ваш путь к классу и используя конструктор следующим образом:
BookClient bookClient = Feign.builder() .client(RibbonClient.create()) .target(BookClient.class, "http://localhost:8081/api/books");
Для обнаружения служб мы должны создать наш сервис с включенной поддержкой Spring Cloud Netflix Eureka. Затем просто интегрируйтесь с Spring Cloud Netflix. В результате мы получаем бесплатную балансировку нагрузки на ленту. Подробнее об этом можно узнать здесь .
8. Заключение
В этой статье мы объяснили, как создать декларативный HTTP-клиент, используя притворство для использования текстовых API.
Как обычно, все примеры кода, показанные в этом руководстве, доступны на GitHub.