What is Feign
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters
used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.
Reference : Declarative REST Client: Feign
Create Feign Consumer Application
Create a new application - feign-consumer, pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>feign-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>feign-consumer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application Configuration
Application configuration in application.yml:
spring:
application:
name: feign-consumer
server:
port: 10201
eureka:
client:
registerWithEureka: false
fetchRegistry: true
service-url:
defaultZone: http://eureka-peer1:8761/eureka/,http://eureka-peer2:8762/eureka/
feign:
hystrix:
enabled: true
Setup
We will have three java files in this demo project.
FeignConsumerApplication.java
GreetingServiceHystrix.java
GreetingService.java
Include Feign in Application
To include and enable feign client in FeignConsumerApplication.java
:
@SpringBootApplication
@EnableFeignClients
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
@RestController
public class FeignConsumerController {
@Autowired
GreetingService greetingService;
@RequestMapping(value="/greeting", method = RequestMethod.GET)
public String greeting() {
return greetingService.greeting();
}
@RequestMapping(value="/greeting/{name}", method = RequestMethod.GET)
public String greeting(@PathVariable String name) {
return greetingService.greeting(name);
}
}
}
Binding Services
Create interface for accessing the Eureka-Service which we have setup in Crash Course - Spring Cloud Netflix Eureka - Part 2/3.
GreetingService.java
@FeignClient(name = "eureka-service", fallback = GreetingServiceHystrix.class)
public interface GreetingService {
@RequestMapping(value = "/greeting", headers = "accept=text/plain")
String greeting();
@RequestMapping(value = "/greeting/{name}", headers = "accept=text/plain")
String greeting(@PathVariable String name);
}
!!!Note!!!
I have faced the issue of feign.FeignException: status 406
. Finally I found I have to setting the headers for accessing the service url:
headers = "accept=text/plain"
Feign Hystrix Fallbacks
Looking at the @FeignClient(name = "eureka-service", fallback = GreetingServiceHystrix.class)
, we enable the fallback handling for @FeignClient.
Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given @FeignClient set the fallback attribute to the class name that implements the fallback.
GreetingServiceHystrix.java
@Component
public class GreetingServiceHystrix implements GreetingService {
@Override
public String greeting() {
return "Eureka-service is not available";
}
@Override
public String greeting(String name) {
return greeting();
}
}
Note! To enable Feign Hystrix Support you need to add following content into application.yml
feign:
hystrix:
enabled: true
Test Feign Consumer
http://localhost:10201/greeting/lee
When Service is available
Results when service is available:
Hello lee! I’m service from port : 10072
When Service is offline
We shutdown the service instances, we expect the fallback handling shall works:
Eureka-service is not available
Checkout the Source