Feign is a Java-to-HTTP client binder that simplifies the process of making HTTP API calls. Inspired by Retrofix, JAXRS-2.0, and WebSocket technologies, Feign provides a declarative API interface style, making it easier to bind Java HTTP clients to your application logic.
Source code: https://github.com/OpenFeign/feign
This chapter builds upon the previous microservices setup. You should have completed the Eureka service registry and Ribbon load balancing configuration.
Creating the Feign Client Module
Create a new module named cloud-feign-consumer. Update the parent pom and add the required dependencies:
<?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>cloud-feign-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cloud-feign-consumer</name>
<description>Feign Consumer Module for Spring Cloud</description>
<parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Configuration File
Create the application.yml with the following settings:
server:
port: 8765
spring:
application:
name: cloud-feign-consumer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
Enabling Feign Clients
Add the @EnableFeignClients annotation to the main application class to enable Feign client functionality:
@EnableFeignClients
@SpringBootApplication
public class CloudFeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(CloudFeignConsumerApplication.class, args);
}
}
Defining the Feign Interface
Create a Feign client interface to call the cloud-service-producer endpoint. The @FeignClient annotation specifies the target service name:
@Component
@FeignClient(value = "cloud-service-producer", configuration = FeignConfiguration.class)
public interface ServiceProducerClient {
@GetMapping(value = "/greet")
String callGreetingEndpoint(@RequestParam(value = "username") String username);
}
Feign Configuration Class
Create a configuration class to customize Feign behavior. This configuration adds retry capability for failed remote calls:
@Configuration
public class FeignConfiguration {
@Bean
public Retryer retryStrategy() {
return new Retryer.Default(100, TimeUnit.SECONDS.toMillis(1), 5);
}
}
Service Layer
Create a service class that uses the Feign client to make remote calls:
@Service
public class GreetingService {
@Autowired
private ServiceProducerClient producerClient;
public String fetchGreeting(String username) {
return producerClient.callGreetingEndpoint(username);
}
}
Controller Layer
Create a REST controller to expose the greeting endpoint:
@RestController
public class GreetingController {
@Autowired
private GreetingService greetingService;
@GetMapping("/greet")
public String greet(@RequestParam(defaultValue = "defaultuser", required = false) String username) {
return greetingService.fetchGreeting(username);
}
}
Testing the Setup
Start the following services in order:
- Eureka Server on port 8761
- Two instances of cloud-service-producer on ports 8762 and 8763
- cloud-feign-consumer on port 8765
Access http://localhost:8765/greet multiple times. You will observe the responses alternating between the two service producer instances.
This demonstrates that Feign Client successfully performs load-balanced remote calls to the cloud-service-producer service across multiple instances.
Implementation Overview
The Feign integration works through the following process:
- The
@EnableFeignClientsannotation activates Feign client scanning during application startup. - Interfaces annotated with
@FeignClientare processed according to Feign's rules. - Package scanning identifies all
@FeignClientannotated interfaces and registers them in the Spring container. - When a interface method is invoked, JDK dynamic proxies generate a
RequestTemplateobject. - The
RequestTemplateis converted into an HTTP request. - The request is handled by a Client implementation, which can use HttpURLConnection, HttpClient, or OkHttp.
- The Client is wrapped in
LoadBalanceClient, which combines with Ribbon to provide load balancing capabilities.