Перейти к основному содержимому

Введение в Spring Cloud OpenFeign

· 7 мин. чтения

1. Обзор

В этом руководстве мы собираемся описать Spring Cloud OpenFeign — декларативный клиент REST для приложений Spring Boot.

Feign упрощает написание клиентов веб-сервисов благодаря поддержке подключаемых аннотаций, включая аннотации Feign и аннотации JAX-RS.

Кроме того, Spring Cloud добавляет поддержку аннотаций Spring MVC и использования тех же HttpMessageConverters , что и в Spring Web.

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

2. Зависимости

Во- первых, мы начнем с создания веб-проекта Spring Boot и добавления зависимости spring-cloud-starter-openfeign в наш файл pom.xml :

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

Кроме того, нам нужно добавить 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>

Мы можем найти последние версии зависимостей spring-cloud-starter-openfeign и spring-cloud на Maven Central.

3. Притвориться клиентом

Далее нам нужно добавить @EnableFeignClients в наш основной класс:

@SpringBootApplication
@EnableFeignClients
public class ExampleApplication {

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

С помощью этой аннотации мы включаем сканирование компонентов для интерфейсов, которые заявляют, что они являются клиентами Feign.

Затем мы объявляем клиента Feign с помощью аннотации @FeignClient :

@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);
}

В этом примере мы настроили клиент для чтения из JSONPlaceholder API .

Аргумент value , передаваемый в аннотации @FeignClient , является обязательным произвольным именем клиента, а с аргументом url мы указываем базовый URL-адрес API.

Кроме того, поскольку этот интерфейс является клиентом Feign, мы можем использовать аннотации Spring Web для объявления API, к которым мы хотим обратиться.

4. Конфигурация

Теперь очень важно понимать, что каждый клиент Feign состоит из набора настраиваемых компонентов.

Spring Cloud создает новый набор по умолчанию по запросу для каждого именованного клиента, используя класс FeignClientsConfiguration , который мы можем настроить, как описано в следующем разделе.

Приведенный выше класс содержит следующие bean-компоненты:

  • Декодер — ResponseEntityDecoder , который обертывает SpringDecoder , используемый для декодирования ответа .
  • Encoder — SpringEncoder используется для кодирования RequestBody .
  • Регистратор — Slf4jLogger — это регистратор по умолчанию, используемый Feign.
  • Contract — SpringMvcContract , обеспечивающий обработку аннотаций
  • Feign-Builder — HystrixFeign.Builder используется для создания компонентов.
  • Клиент — LoadBalancerFeignClient или клиент Feign по умолчанию.

4.1. Пользовательская конфигурация бинов

Если мы хотим настроить один или несколько из этих bean-компонентов , мы можем переопределить их с помощью класса @Configuration , который затем добавим в аннотацию FeignClient :

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

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

В этом примере мы указываем Feign использовать OkHttpClient вместо клиента по умолчанию для поддержки HTTP/2.

Feign поддерживает несколько клиентов для разных вариантов использования, включая ApacheHttpClient , который отправляет больше заголовков с запросом, например, Content-Length , что ожидают некоторые серверы.

Чтобы использовать эти клиенты, давайте не забудем добавить необходимые зависимости в наш файл pom.xml :

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

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

Мы можем найти последние версии feign-okhttp и feign-httpclient на Maven Central.

4.2. Конфигурация с использованием свойств

Вместо использования класса @Configuration мы можем использовать свойства приложения для настройки клиентов Feign , как показано в этом примере application.yaml :

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

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

Наконец, мы можем создать конфигурацию с именем клиента по умолчанию для настройки всех объектов @FeignClient , или мы можем объявить фиктивное имя клиента для конфигурации:

feign:
client:
config:
jplaceholder:

Если у нас есть как bean-компонент @Configuration , так и свойства конфигурации, свойства конфигурации переопределяют значения @Configuration .

5. Перехватчики

Добавление перехватчиков — еще одна полезная функция, предоставляемая Feign.

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

В этом разделе мы реализуем наш собственный перехватчик, а также используем готовый вариант, предоставляемый Spring Cloud OpenFeign. Оба будут добавлять базовый заголовок аутентификации к каждому запросу.

5.1. Реализация RequestInterceptor

Давайте реализуем наш собственный перехватчик запросов:

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

Кроме того, чтобы добавить перехватчик в цепочку запросов, нам просто нужно добавить этот bean-компонент в наш класс @Configuration или, как мы видели ранее, объявить его в файле свойств:

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

5.2. Использование BasicAuthRequestInterceptor

В качестве альтернативы мы можем использовать класс BasicAuthRequestInterceptor , который предоставляет Spring Cloud OpenFeign:

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

Это просто. Теперь все запросы будут содержать базовый заголовок аутентификации.

6. Поддержка Hystrix

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

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

Для достижения цели нам нужно включить Hystrix, добавив feign.hystrix.enabled=true в файл свойств.

Это позволяет нам реализовать резервные методы, которые вызываются при сбое службы:

@Component
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {

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

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

Чтобы сообщить Feign, что резервные методы были предоставлены, нам также нужно установить наш резервный класс в аннотации @FeignClient :

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

7. Ведение журнала

Для каждого клиента Feign по умолчанию создается логгер.

Чтобы включить ведение журнала, мы должны объявить его в файле application.propertie s, используя имя пакета клиентских интерфейсов:

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

Или, если мы хотим включить ведение журнала только для одного конкретного клиента в пакете, мы можем использовать полное имя класса:

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

Обратите внимание, что ведение журнала Feign отвечает только на уровень DEBUG .

Logger.Level , который мы можем настроить для каждого клиента, указывает, сколько нужно регистрировать:

@Configuration
public class ClientConfiguration {

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

На выбор предлагается четыре уровня ведения журнала:

  • NONE — без ведения журнала, значение по умолчанию.
  • BASIC — протоколировать только метод запроса, URL-адрес и статус ответа.
  • ЗАГОЛОВКИ — регистрируйте основную информацию вместе с заголовками запросов и ответов.
  • ПОЛНЫЙ — протоколировать тело, заголовки и метаданные как для запроса, так и для ответа

8. Обработка ошибок

Обработчик ошибок Feign по умолчанию, ErrorDecoder.default , всегда генерирует FeignException .

Это поведение не всегда самое полезное. Итак, чтобы настроить выбрасываемое исключение, мы можем использовать 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");
}
}
}

Затем, как мы делали ранее, мы должны заменить ErrorDecoder по умолчанию, добавив bean-компонент в класс @Configuration :

@Configuration
public class ClientConfiguration {

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

9. Заключение

В этой статье мы обсудили Spring Cloud OpenFeign и его реализацию в простом примере приложения.

Мы также увидели, как настраивать клиент, добавлять перехватчики к нашим запросам и обрабатывать ошибки с помощью Hystrix и ErrorDecoder .

Как обычно, все примеры кода, показанные в этом руководстве, доступны на GitHub .