Introduzione a Spring Cloud OpenFeign

1. Panoramica

In questo tutorial descriveremo Spring Cloud OpenFeign, un client REST dichiarativo per le app Spring Boot.

Feign semplifica la scrittura di client di servizi Web con il supporto per annotazioni collegabili, che include annotazioni Feign e annotazioni JAX-RS.

Inoltre, Spring Cloud aggiunge il supporto per le annotazioni Spring MVC e per l'utilizzo degli stessi HttpMessageConverters usati in Spring Web.

Una cosa grandiosa dell'utilizzo di Feign è che non dobbiamo scrivere alcun codice per chiamare il servizio, a parte una definizione dell'interfaccia.

2. Dipendenze

Innanzitutto, inizieremo creando un progetto web Spring Boot e aggiungendo la dipendenza spring-cloud-starter-openfeign al nostro file pom.xml :

 org.springframework.cloud spring-cloud-starter-openfeign 

Inoltre, dovremo aggiungere le dipendenze spring-cloud :

    org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import   

Possiamo trovare le ultime versioni di spring-cloud-starter-openfeign e spring-cloud-dependencies su Maven Central.

3. Finto cliente

Successivamente, dobbiamo aggiungere @EnableFeignClients alla nostra classe principale:

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

Con questa annotazione, abilitiamo la scansione dei componenti per le interfacce che dichiarano di essere client Feign.

Quindi, dichiariamo un client Feign utilizzando l' annotazione @FeignClient :

@FeignClient(value = "jplaceholder", url = "//jsonplaceholder.typicode.com/") public interface JSONPlaceHolderClient { @RequestMapping(method = RequestMethod.GET, value = "/posts") List getPosts(); @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json") Post getPostById(@PathVariable("postId") Long postId); }

In questo esempio, abbiamo configurato un client per leggere dalle API JSONPlaceHolder.

L' argomento valore passato nell'annotazione @FeignClient è un nome client obbligatorio e arbitrario, mentre con l' argomento url specifichiamo l'URL di base dell'API.

Inoltre, poiché questa interfaccia è un client Feign, possiamo usare le annotazioni Web Spring per dichiarare le API a cui vogliamo rivolgerci.

4. Configurazione

Ora, è molto importante capire che ogni cliente Feign è composto da un set di componenti personalizzabili.

Spring Cloud crea un nuovo set predefinito su richiesta per ogni client nominato utilizzando la classe FeignClientsConfiguration che possiamo personalizzare come spiegato nella sezione successiva.

La classe precedente contiene questi fagioli:

  • Decoder - ResponseEntityDecoder , che avvolge SpringDecoder, utilizzato per decodificare il Response
  • Encoder - SpringEncoder , utilizzato per codificare RequestBody
  • Logger - Slf4jLogger è il logger predefinito utilizzato da Feign
  • Contratto: SpringMvcContract , che fornisce l'elaborazione delle annotazioni
  • Feign-Builder - HystrixFeign.Builder utilizzato per costruire i componenti
  • Client: LoadBalancerFeignClient o client Feign predefinito

4.1. Configurazione fagioli personalizzati

Se vogliamo personalizzare uno o più di questi bean, possiamo sovrascriverli usando una classe @Configuration , che poi aggiungiamo all'annotazione FeignClient :

@FeignClient(value = "jplaceholder", url = "//jsonplaceholder.typicode.com/", configuration = MyClientConfiguration.class)
@Configuration public class MyClientConfiguration { @Bean public OkHttpClient client() { return new OkHttpClient(); } }

In questo esempio, diciamo a Feign di usare OkHttpClient invece di quello predefinito per supportare HTTP / 2.

Feign supporta più client per diversi casi d'uso, incluso ApacheHttpClient , che invia più intestazioni con la richiesta, ad esempio Content-Length, previsto da alcuni server.

Per utilizzare questi client, non dimentichiamoci di aggiungere le dipendenze richieste al nostro file pom.xml , ad esempio:

 io.github.openfeign feign-okhttp   io.github.openfeign feign-httpclient 

Possiamo trovare le ultime versioni di feign-okhttp e feign-httpclient su Maven Central.

4.2. Configurazione mediante proprietà

Invece di usare una classe @Configuration , possiamo usare le proprietà dell'applicazione per configurare i client Feign , come mostrato in questo esempio application.yaml :

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

Con questa configurazione, stiamo impostando i timeout su 5 secondi e il livello del logger su base per ogni client dichiarato nell'applicazione.

Infine, possiamo creare la configurazione con default come nome del client per configurare tutti gli oggetti @FeignClient , oppure possiamo dichiarare il falso nome del client per una configurazione:

feign: client: config: jplaceholder:

Se abbiamo sia il bean @Configuration che le proprietà di configurazione, le proprietà di configurazione sovrascriveranno i valori di @Configuration .

5. Intercettori

L'aggiunta di intercettori è un'altra utile funzionalità fornita da Feign.

Gli intercettatori possono eseguire una varietà di attività implicite, dall'autenticazione alla registrazione, per ogni richiesta / risposta HTTP.

In questa sezione, implementeremo il nostro intercettore, oltre a utilizzare quello fornito da Spring Cloud OpenFeign out-of-the-box. Entrambi aggiungeranno un'intestazione di autenticazione di base a ciascuna richiesta .

5.1. Implementazione di RequestInterceptor

Quindi, nello snippet di seguito, implementiamo il nostro intercettatore di richieste personalizzato:

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

Also, to add the interceptor to the request chain, we just need to add this bean to our @Configuration class, or as we saw previously, declare it in the properties file:

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

5.2. Using BasicAuthRequestInterceptor

Alternatively, we can use the BasicAuthRequestInterceptor class that the Spring Cloud OpenFeign provides:

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

It's simple as that! Now all the requests will contain the basic authentication header.

6. Hystrix Support

Feign supports Hystrix, so if we have enabled it, we can implement the fallback pattern.

With the fallback pattern, when a remote service call fails, rather than generating an exception, the service consumer will execute an alternative code path to try to carry out the action through another means.

To achieve the goal, we need to enable Hystrix adding feign.hystrix.enabled=true in the properties file.

This allows us to implement fallback methods that are called when the service fails:

@Component public class JSONPlaceHolderFallback implements JSONPlaceHolderClient { @Override public List getPosts() { return Collections.emptyList(); } @Override public Post getPostById(Long postId) { return null; } }

To let Feign know that fallback methods have been provided, we also need to set our fallback class in the @FeignClient annotation:

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

7. Logging

For each Feign client, a logger is created by default.

To enable logging, we should declare it in the application.properties file using the package name of the client interfaces:

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

Or, if we want to enable logging only for one particular client in a package, we can use the full class name:

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

Note that Feign logging responds only to the DEBUG level.

The Logger.Level that we may configure per client indicates how much to log:

@Configuration public class ClientConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.BASIC; } }

There are four logging levels to choose from:

  • NONE – no logging, which is the default
  • BASIC – log only the request method, URL, and response status
  • HEADERS – log the basic information together with request and response headers
  • FULL – log the body, headers, and metadata for both request and response

8. Error Handling

Feign's default error handler, ErrorDecoder.default, always throws a FeignException.

Now, this behavior isn't always the most useful. So, to customize the Exception thrown, we can use a 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"); } } }

Quindi, come abbiamo fatto in precedenza, dobbiamo sostituire il ErrorDecoder predefinito aggiungendo un bean alla classe @Configuration :

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

9. Conclusione

In questo articolo, abbiamo discusso di Spring Cloud OpenFeign e della sua implementazione in una semplice applicazione di esempio.

Inoltre, abbiamo visto come configurare un client, come aggiungere intercettori alle nostre richieste e come gestire gli errori utilizzando Hystrix e ErrorDecoder.

Come al solito, tutti gli esempi di codice mostrati in questo tutorial sono disponibili su GitHub.