Добавить в корзинуПозвонить
Найти в Дзене
Nuances of programming

Создание REST-клиента с помощью Spring Cloud OpenFeign и Netflix Ribbon

В Java HTTP-запросы между сервисами реализуются весьма просто. Так как существует ряд известных открытых HTTP-клиентов, таких как OkHttp и RestTemplate в Spring, то сложность представляет не выбор подходящего кандидата, а дальнейшая с ним работа.
Оглавление

Источник: Nuances of Programming

В Java HTTP-запросы между сервисами реализуются весьма просто. Так как существует ряд известных открытых HTTP-клиентов, таких как OkHttp и RestTemplate в Spring, то сложность представляет не выбор подходящего кандидата, а дальнейшая с ним работа.

Среди растущего числа распределенных облачных сервисов, где сервера постоянно появляются и исчезают, конечные точки сервисов оказываются динамичны и их сложно знать наперед. По этой причине, прежде чем отправлять запрос сервису, REST-клиенту необходимо интегрироваться в реестр сервисов и находить там его конечную точку.

Помимо этого, нужно обработать сериализацию запрос-ответ, а также реализовать балансировку нагрузки, правильно распределив ее между серверами. Плюсом же к этому нужно организовать систему отказоустойчивости. Все перечисленное представляет собой сквозную функциональность распределенных систем.

Именно здесь на помощь приходит Spring Cloud OpenFeign. Это не просто HTTP-клиент, а целостное решение задач, сопутствующих современным REST-клиентам. Spring Cloud OpenFeign обеспечивает интеграцию OpenFeign для Spring Boot путем автоматической настройки и привязки к среде Spring.

Сервис OpenFeign, изначально известный как Feign, является детищем Netflix. Он позволяет разработчикам использовать декларативный способ построения HTTP-клиентов с помощью аннотированных интерфейсов и без шаблонного кода. Spring Cloud OpenFeign обеспечивает балансировку нагрузки с помощью Ribbon и очень удобно интегрируется с другими облачными службами, например с Eureka для обнаружения сервисов и Hystrix для отказоустойчивости. Все это предусмотрено в OpenFeign изначально и не требует прописывания дополнительного кода.

В текущей статье вы узнаете:

  • Как с помощью Spring Cloud OpenFeign построить декларативный легко читаемый REST-клиент для вызова сервисов по HTTP.
  • Как настроить Ribbon и конечные точки для балансировки нагрузки.
  • Как активировать Eureka-клиент в вашем сервисе Spring REST для интеграции с Eureka Server.

Создание Maven-проекта

Для генерации Maven-проекта со Spring Boot 2.x можно использовать Spring Initializr. Добавьте в этот проект зависимости Spring Web, OpenFeign и Ribbon.

Spring Initializr  —  добавление зависимостей
Spring Initializr  —  добавление зависимостей

Если вы начинаете Maven-проект с нуля, то импортируйте Spring Cloud Dependencies POM, чтобы он наследовал все версии артефактов семейства Spring CLoud.

Далее добавьте к зависимостям проекта модули Spring Boot Starter Web, Spring Cloud Starter OpenFeign и Spring Cloud Starter Netflix Ribbon.

В качестве альтернативы можете загрузить весь проект с GitHub .

Создание класса Application для запуска

Как и в любом приложении Spring Boot, для запуска ApplicationContext необходим основной класс. Создайте его с помощью аннотации @SpringBootApplication , добавив главный метод, вызывающий SpringApplication.run() для запуска приложения.

@SpringBootApplication
@EnableFeignClients
public class Application {

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

@SpringBootApplication активирует в приложении сканирование компонентов и автоматическую настройку. Аннотацию @EnableFeignClients мы добавляем, чтобы включить сканирование компонентов для интерфейсов, аннотированных с @FeignClient .

Создание интерфейса REST-клиента

Создайте интерфейс PostmanEchoClient , добавьте к нему аннотацию @FeinClient и назовите ее postman-echo . Spring автоматически просканирует наш интерфейс и создаст реализацию для REST-клиента в среде выполнения.

@FeignClient(name = "postman-echo")
public interface PostmanEchoClient {
}

Spring использует имя postman-echo , сопровождаемое аннотацией @FeignClient в качестве идентификатора, чтобы создать RibbonClient для клиентского балансировщика нагрузки.

Есть несколько способов предоставить RibbonClient конечную точку сервера для балансировки нагрузки, например использовать настройки Java, свойства приложения Spring или интеграцию с Eureka Server для поиска этой конечной точки.

Чтобы перейти от жестко закодированного URL конечной точки сервера к решению с балансировкой нагрузки, давайте настроим Ribbon со статическим listOfServers . В разделе src/main/resources файла application.yaml добавьте следующие свойства:

postman+echo:
ribbon:
listOfServers:
https://postman-echo.com/, https://postman-echo.com/

Postman Echo  —  это сервис, который можно использовать для тестирования REST-клиентов и совершения пробных вызовов API. Он предоставляет конечные точки для GET , POST и PUT с различными механизмами аутентификации.

На официальном сайте Postman Echo можно найти всю документацию по конечным точкам вместе с примерами ответов.

Добавление клиентского метода GET-запроса

Далее добавьте в интерфейсе клиента Postman Echo клиентский метод getEcho , который принимает параметры запроса String foo и String bar , возвращая объект EchoGetResponse . Прикрепите к этому GET-запросу path /get при помощи аннотации GetMapping . При вызове этот метод будет вызывать конечную точку GET-запроса Postman Echo.

@GetMapping(
path = "/get",
consumes = "application/json")
EchoGetResponse getEcho(
@RequestParam("foo") String foo,
@RequestParam("bar") String bar
);

Конечная точка GET-запроса Postman Echo будет повторять все переданные параметры запроса в теле ответа в элементе args . Документация по GET-запросу Postman Echo лежит здесь .

{
"args": {
"foo": "abc",
"bar": "123"
}
}

Создайте новый класс EchoGetResponse , который будет представлять ответ JSON. EchoGetResponse  —  это класс простого Java-объекта (POJO). Ответ JSON будет десериализован в нашем методе GET-запроса Postman Echo как EchoGetResponse .

Тестирование метода GET-запроса с помощью ‘SpringBootTest’

Мы тестируем вызов клиентского метода GET-запроса к удаленной конечной точке с помощью SpringBootTest . Для этого нужно создать класс PostmanEchoClientTests . Установите для теста случайный порт с помощью аннотации @SpringBootTest .

@SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT)
class PostmanEchoClientTests {
}

Выполните автоматическое внедрение (autowire) созданного Spring bean-компонента PostmanEchoClient в класс модульного теста. Bean-компонент должен использовать настроенный список серверов Ribbon для балансировки нагрузки на клиентской стороне.

@Autowired private PostmanEchoClient client;

Создайте метод getEcho с аннотацией @Test , использующий внедренный bean-компонент PostmanEchoClient для вызова конечной точки GET-запроса Postman Echo.

После вызова конечной точки проверьте, совпадает ли возвращаемый ответ EchoGetResponse с переданными аргументами запроса, убедившись, что он правильно десериализован из ожидаемого содержимого JSON.

Добавление клиентского метода POST-запроса

Теперь, протестировав GET, давайте перейдем к запросу POST. Добавьте в интерфейс PostmanEchoClient клиентский метод postEcho , принимающий параметры запроса String foo и String bar . У него должно быть тело запроса объекта EchoPostRequest , а возвращаться им должен объект EchoPostResponse .

Добавьте к этому POST-запросу path /post при помощи аннотации @PostMapping . При вызове этот клиентский метод будет вызывать конечную точку POST-запроса Postman Echo.

Конечная точка будет повторять переданные параметры и body запроса в виде ответа в элементах args и data .

Создайте новый класс EchoPostRequest , который будет представлять тело JSON-запроса. EchoPostRequest  —  это класс простого объекта Java (POJO), содержащий одно свойство сообщения String . При вызове к конечной точке POST-запроса Postman Echo объект EchoPostRequest будет сериализован в тело JSON-запроса.

Создайте другой класс EchoPostResponse , который будет представлять ответ JSON. Этот класс содержит args со свойствами foo и bar , а также data со свойством message . Ответ JSON будет десериализован как EchoPostResponse в нашем клиентском методе Post-запроса Postman Echo.

Тестирование метода POST-запроса с помощью ‘SpringBootTest’

Снова включаем метод теста postEcho в ранее добавленный класс PostmanEchoClientTests для только что добавленного клиентского метода postEcho . Как и ранее используйте для вызова конечной точки POST-запроса Postman Echo автоматическое внедрение PostmanEchoClient .

После вызова удаленной точки убедитесь, что возвращаемый ответ EchoPostResponse совпадает с переданными аргументами и телом запроса, подтверждающими его верную десериализацию из ожидаемого формата JSON.

Интеграция с Eureka Server

С помощью простой аннотации и некоторой настройки можно быстро активировать в сервисе Spring REST клиента Netflix Eureka Discovery.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Далее добавьте в класс application аннотацию @EnableDiscoveryClient , чтобы активировать реализацию клиента Netflix Eureka Discovery. Затем он зарегистрируется в реестре сервисов Netflix Eureka Server и будет использовать абстракцию Spring Cloud DiscoveryClient для запроса метаданных, содержащих конечные точки сервисов, которые клиент Ribbon будет использовать для балансировки нагрузки.

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class Application {

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

И наконец, укажите имя приложения и URL конечной точки Eureka Server в application.yaml .

Клиент Eureka использует имя приложения для регистрации на Eureka Server. Если это имя не указать, ваш сервис будет отображаться на Eureka Server как неизвестный.

spring:
application:
name: feignclient

eureka:
client:
serviceUrl:
defaultZone:
http://localhost:8761/eureka

Проделав эти несколько шагов, вы интегрировали сервис Spring REST в Eureka Server.

Теперь, когда ваш REST-сервис готов к подключению к Eureka Server, нужно удалить свойство listOfServers для Ribbon из application.yaml или закомментировать его.

# postmanEcho:
# ribbon:
# listOfServers:
https://postman-echo.com/

Создание Eureka Server

Создайте с помощью Spring Initializr другой проект  —  на этот раз для Eureka Server, добавив в него зависимость Eureka Server.

Spring Initialzr  —  добавление зависимостей
Spring Initialzr  —  добавление зависимостей

Если вы начинаете новый Maven-проект, импортируйте Spring Cloud Dependencies POM и добавьте зависимость Spring Cloud Starter Netflix Eureka Server.

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

В качестве альтернативы можно загрузить проект Eureka Server с GitHub .

Вам нужно создать стандартный класс точки входа с аннотацией @SpringBootApplication . Для активации реализации Eureka Server также добавьте в него аннотацию @EnableEurekaServer .

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {

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

Далее измените порт сервера на 8761 .

server:
port: 8761

Наконец, деактивируйте в application.yaml функции саморегистрации и запроса реестра.

eureka:
client:
serviceUrl:
defaultZone:
http://localhost:8761/eureka
registerWithEureka: false
fetchRegistry: false

Теперь Eureka Server готов, можете запускать!

Поскольку Postman Echo является внешним сервисом, нужно вручную зарегистрировать его на Eureka Server. Список REST-операций, поддерживаемых Eureka, можно найти здесь . Этот API понадобится вам только для регистрации нового приложения.

Отправьте с помощью Postman запрос на Eureka Server.

Postman  —  запрос на Eureka Server
Postman  —  запрос на Eureka Server

URL для регистрации Postman Echo на Eureka Server следующий:

http://localhost:8761/eureka/apps/POSTMAN-ECHO

Запросите содержимое для регистрации Postman Echo на Eureka Server так:

Нужно зарегистрировать приложение как POSTMAN-ECHO , потому что ранее мы назвали @FeignClient как postman-echo .

В результате вы должны получить успешный ответ без содержимого.

Postman — ответ от Eureka Server
Postman — ответ от Eureka Server

Откройте панель Eureka, где должна отразиться регистрация POSTMAN-ECHO .

Eureka Server  —  зарегистрированные инстансы
Eureka Server  —  зарегистрированные инстансы

Еще раз запустите PostmanRestClientTests , чтобы убедиться, что все работает как надо.

Заключение

Мы научились создавать декларативного REST-клиента при помощи Spring Cloud OpenFeign, задействовав Spring Cloud Netflix Ribbon для обеспечения на клиентской стороне балансировки нагрузки и отказоустойчивости. Плюсом к этому мы узнали, как настраивать конечную точку статического сервера для Ribbon и как выполнять интеграцию с Eureka Server для получения списка конечных точек зарегистрированных серверов. Весь исходный код доступен на GitHub .

Благодарю за чтение и надеюсь, что статья оказалась для вас полезна.

Читайте также:

Читайте нас в Telegram , VK

Перевод статьи Andy Lian : Building a REST Client with Spring Cloud OpenFeign and Netflix Ribbon