A Guide to Spring Cloud OpenFeign

Spring Cloud OpenFeign is a declarative HTTP client provided by the Spring Cloud ecosystem. It allows you to write web service clients by defining Java interfaces, abstracting away the need for manually writing REST client code using RestTemplate or WebClient.

In this post, I will cover common uses of Spring Cloud OpenFeign. This post is based on Java 21, Spring Boot 3.5.3, and Spring Cloud 2025.0.0.

Next, I will use a simple example application to show it in action.

1. Create Project and Add Dependencies

Using Gradle

1. Create a Java application with the gradle init command.

$ mkdir spring-cloud-open-feign && cd spring-cloud-open-feign
$ gradle --configuration-cache \
init --use-defaults \
--type java-application \
--package com.taogen.springcloud

2. Gradle configuration

app/build.gradle.kts

plugins {
java
id("org.springframework.boot") version "3.5.3"
// Use the Spring Dependency Management plugin to manage Spring Cloud dependencies.
id("io.spring.dependency-management") version "1.1.7"
}

extra["springCloudVersion"] = "2025.0.0"

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

repositories {
mavenCentral()
}

dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
}
}

tasks.withType<Test> {
useJUnitPlatform()
}

Using Maven

1. Create a Java application with mvn command.

$ mvn -B archetype:generate \
-DgroupId=com.taogen.springcloud \
-DartifactId=spring-cloud-open-feign \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.5

2. Maven configuration

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.taogen.springcloud</groupId>
<artifactId>spring-cloud-open-feign</artifactId>
<version>1.0-SNAPSHOT</version>

<name>spring-cloud-open-feign</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
<java.version>21</java.version>
<spring-boot.version>3.5.3</spring-boot.version>
<spring-cloud.version>2025.0.0</spring-cloud.version>
</properties>

<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.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>

Using Spring Initializr

Go to https://start.spring.io/

Project Metadata

  • Group: com.taogen.springcloud
  • Artifact: spring-cloud-open-feign

Add dependencies

  • OpenFeign
  • Eureka Discovery Client
  • Spring Web
  • Spring Boot Actuator

2. Spring Configuration

The spring configuration is the same as the Eureka client spring configuration.

application.yml

spring:
application:
name: spring-cloud-open-feign
server:
# configure the service to use a random port number
port: 0

# Eureka client
eureka:
instance:
preferIpAddress: true
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
healthcheck:
enabled: true

# Actuator
management:
endpoints:
web:
exposure:
include: health,info,beans

3. The Application

1. Spring Boot application entry point

SpringCloudOpenFeignApplication.java

package com.taogen.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class SpringCloudOpenFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudOpenFeignApplication.class, args);
}
}
  • @EnableFeignClients: To enable Open Feign.

2. Define a Feign Client interface with @FeignClient

GreetingClient.java

package com.taogen.springcloud;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient("eureka-client-2")
public interface GreetingClient {
@GetMapping("/greeting")
String greeting();
}

3. Using the Feign Client

package com.taogen.springcloud;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class MyController {
private final GreetingClient greetingClient;

public MyController(GreetingClient greetingClient) {
this.greetingClient = greetingClient;
}

@RequestMapping("/callEurekaClient2UsingOpenFeign")
public String callEurekaClient2UsingOpenFeign() {
return greetingClient.greeting();
}
}

4. Start and Verification

1. Starting a Eureka server and two instances of Eureka-Client-2. And write a greeting API in Eureka-Client-2. For using Eureka, you can refer to A Guide to Spring Cloud Netflix Eureka.

The greeting API in Eureka Client 2

@RestController  
@RequestMapping("/")
public class MyController {
@Value("${spring.application.name}")
private String applicationName;

@GetMapping("/greeting")
public String greeting(){
System.out.println("greeting method is called");
return "Hello from " + applicationName + new Date();
}
}

Starting two instances of Eureka-Client-2 with the following command. Running the command in two terminal tabs to start two instances.

Gradle

./gradlew bootRun

Maven

mvn spring-boot:run

2. Running the main() method in the SpringCloudOpenFeignApplication to start this Spring Cloud OpenFeign application.

3. Request the /callEurekaClient2UsingOpenFeign endpoint to see the result of using a client-side load balancer to call Eureka client 2 instances.

References

[1] Spring Microservices in Action, Second Edition

[2] Spring Cloud OpenFeign Documentation