Using Feign Client for Declarative REST Calls in Spring Cloud

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:

  1. Eureka Server on port 8761
  2. Two instances of cloud-service-producer on ports 8762 and 8763
  3. 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:

  1. The @EnableFeignClients annotation activates Feign client scanning during application startup.
  2. Interfaces annotated with @FeignClient are processed according to Feign's rules.
  3. Package scanning identifies all @FeignClient annotated interfaces and registers them in the Spring container.
  4. When a interface method is invoked, JDK dynamic proxies generate a RequestTemplate object.
  5. The RequestTemplate is converted into an HTTP request.
  6. The request is handled by a Client implementation, which can use HttpURLConnection, HttpClient, or OkHttp.
  7. The Client is wrapped in LoadBalanceClient, which combines with Ribbon to provide load balancing capabilities.

Tags: Spring Cloud feign Declarative Client microservices REST API

Posted on Thu, 05 Nov 2026 16:45:42 +0000 by phpSensei