Spring Cloud Netflix: Feign по-русски

Kirill Sereda
4 min readJun 4, 2019

--

Привет.

Я хочу продолжить серию из предыдущих статей по Netflix, а именно поговорить про Feign Client.

На русском языке очень мало информации по стеку Netflix.

И правильно, потому что надо читать официальную документацию, там вы найдете больше всего. Но я все же решил рассказать “своими словами” чтобы сложилась более ясная картина при изучении данного стека для тех, кто предпочитает русскоязычную литературу.

Планирую обновлять статьи по мере изучения нового материала. Если у вас есть предложения на этот счет, буду рад выслушать.

Другие реализации Feign Client я рассмотрел в другой статье:

Feign Client + Hystrix link

Feign — простой и гибкий http-клиент, который нативно интегрирован с Ribbon (О нем в другой статье).
Feign использует интерфейсы аннотированные @FeignClient чтобы генерировать API запросы и мапить ответ на Java классы.
Он шлет http запросы другим сервисам.

Его особенность в том, что нам не нужно знать где и на каком порту находится какой-то сервис.
Мы просто говорим Feign клиенту, иди к “Джон Уику” и получи у него всех пользователей. Далее Feign обращается к Eureka Server и спрашивает где находится “Джон Уик”.
Если “Джон Уик” регистрировался в Eureka Server, то Eureka будет всё знать о “Джон Уик” (где он находится, на каком порту, его URL и т.д.)

Вам нужно только описать, как получить доступ к удаленной службе API, указав такие детали, как URL, тело запроса и ответа, принятые заголовки и т. д. Клиент Feign позаботится о деталях реализации.

Netflix предоставляет Feign в качестве абстракции для вызовов на основе REST, благодаря которым микросервисы могут связываться друг с другом, но разработчикам не нужно беспокоиться о внутренних деталях REST.

Нужно указать аннотацию @EnableFeignClients над основным классом

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class FeignClientApplication {

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

}

На интерфейс ставим аннотацию @FeignClient(name = “Джон Уик”) и указываем имя того сервиса, который нам нужен (в пояснении я описывал сервис под названием “Джон Уик”). В том сервисе будет выполняться некая логика по работе с базой и настройки коннекта к базе, или получение всех пользователей и т.д.

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

Еще раз: для упрощения связи по REST мы и используем Feign: при помощи него мы будем поглощать сообщения от других сервисов и автоматически превращать их в Java объекты.

Рассмотрим небольшой и в то же время очень простой пример.

У нас есть сервис А и сервис B, которые оба зарегистрированы в Eureka. Мы хотим из сервиса А вызвать сервис B и получить какие-то данные.

Сервис B имеет следующий контроллер:

@RestController
@RequestMapping(“/users/{id}/statistic”)
public class StatisticsController {

@Autowired
StatisticsService statisticsService;

public List<UserStatisticModel> getStatistic(@PathVariable String id) {
List<UserStatisticModel> statisticsList = statisticsService.getAlbums(id);
return statisticsList;
}
}

и модель:

public class UserStatisticModel {

private Long id;
private String userId;
private String username;
private String title;

}

Используем Lombok чтобы избавиться от ненужного кода геттеров и сеттеров.

Чтобы из сервиса А вызвать сервис B мы создадим в сервисе А feign client.

В аннотации @FeignClient мы указываем имя того сервиса, который хотим вызвать (сервис B).

@FeignClient(name = “B”)
public interface ServiceFeignClient {

@GetMapping(“/users/${id}/statistic”)
public List<UserStatisticModel> getStatistic(@PathVariable String id);

}

Аннотация @GetMapping содержит путь, который отображается на тот же самый путь в аннотации @RequestMapping в микросервисе B и указывает, что это будет GET запрос.

Метод должен иметь такую-же сигнатуру что и метод в сервисе B. Это важно!

Модель:

public class UserStatisticModel {

private Long id;
private String userId;
private String username;
private String title;

}

Теперь чтобы создать экземпляр клиента Feign, вам нужно будет автоматически подключить интерфейс клиента feign к вашему классу, в котором вызывается логика.

@Service
public class UsersServiceImpl implements UsersService {

@Autowired
ServiceFeignClient serviceFeignClient;

….

List<AlbumResponseModel> albumsList = serviceFeignClient.getStatistic(userId);

….

}

Теперь когда мы будем дергать URL “/users/${id}/statistic” из ServiceFeignClient сервиса А, он посмотрит на аннотацию @FeignClient(name = “B”) и увидит, что там указан сервис B, пойдет к нему и по этому же URL в StatisticsController вызовет метод getStatistic.

Все очень просто.

Также хочу добавить, если вам нужно использовать внешнюю веб-службу, которая не является частью вашей архитектуры микросервисов и не зарегистрирована в вашей службе Eureka, то используйте URL в качестве параметра аннотации @FeignClient.

@FeignClient(name = “B”, url = “http://lalalala")
public interface ServiceFeignClient {

@GetMapping(“/users/${id}/statistic”)
public List getStatistic(@PathVariable String id);

}

Если вы нашли неточности в описании данной статьи, вы можете написать мне на email и я с радостью вам отвечу.

Kirill Sereda

email: kirill.serada@gmail.com

skype: kirill-sereda

linkedin: www.linkedin.com/in/ksereda

--

--