Mastering OpenFeign: Simplify Spring Cloud REST Calls with Declarative Clients

This guide walks through replacing verbose RestTemplate calls with Spring Cloud OpenFeign's declarative REST client, covering dependency setup, client interfaces, annotations, logging, timeout, retry, interceptors, fallback handling with Sentinel, and advanced configurations to streamline microservice communication.

Java One
Java One
Java One
Mastering OpenFeign: Simplify Spring Cloud REST Calls with Declarative Clients

In the previous lesson the order service invoked the product service using a programmatic RestTemplate call, which required manual URL construction and request handling. This tutorial introduces Spring Cloud OpenFeign, a declarative REST client that reduces boilerplate by using annotations.

1. Remote Call with OpenFeign

First add the OpenFeign starter to the pom.xml of the services module:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Enable Feign clients in the order service's main class:

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

Define a Feign client interface for the product service:

@FeignClient(value = "service-product")
public interface ProductFeignClient {
    @GetMapping("/product/{id}")
    Product getProduct(@PathVariable("id") Long id);
}
Note: The name used in @PathVariable must match the placeholder in the URL, otherwise OpenFeign will fail.

Inject the client into the order service implementation:

@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private ProductFeignClient productFeignClient;

    public Product getProductRemoteLoadBalanceFeign(Long productId) {
        return productFeignClient.getProduct(productId);
    }
}

1.2 Third‑Party Call Example

For services that provide an external API, such as WeChat Pay, you can still use OpenFeign by specifying the full URL:

@FeignClient(name = "pay-client", url = "https://api.mch.weixin.qq.com")
public interface PayFeignClient {
    @PostMapping("/v3/pay/transactions/jsapi")
    String pay(@RequestHeader("Authorization") String authorization,
               @RequestParam("appid") String appid,
               @RequestParam("mchid") String mchid);
}

A simple test class can invoke the client:

@SpringBootTest
public class FeignClientTest {
    @Resource
    private PayFeignClient payFeignClient;

    @Test
    public void payTest() {
        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"1900000001\",...";
        String appId = "wx1234567890123456";
        String mchId = "1900000001";
        String prepayId = payFeignClient.pay(authorization, appId, mchId);
        System.out.println(prepayId);
    }
}

2. Basic Configuration

2.1 Logging

Set the Feign client log level to FULL in application.yml and expose a bean:

logging:
  level:
    com.greenbook.order.feign: debug
@Configuration
public class OrderServiceConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

2.2 Timeout Control

Configure connection and read timeouts to avoid cascading failures:

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            logger-level: full
            connect-timeout: 1000
            read-timeout: 3000
          service-product:
            logger-level: full
            connect-timeout: 3000
            read-timeout: 5000

2.3 Retry Mechanism

Inject a Retryer bean to enable automatic retries. The default implementation uses three parameters: period (initial interval), maxPeriod (maximum interval), and maxAttempts (maximum retries).

@Bean
Retryer retryer() {
    return new Retryer.Default();
}

The default constructor sets period = 100L, maxPeriod = 1s, and maxAttempts = 5. The interval grows by a factor (default 1.5) after each attempt.

3. Advanced Usage

3.1 Interceptor

Implement a request interceptor to add a custom header (e.g., X-Token) to every outgoing request:

@Component
public class XTokenRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        log.info("Entering interceptor, adding X-Token header");
        requestTemplate.header("X-Token", UUID.randomUUID().toString());
    }
}

Register the interceptor either via @Component or explicitly in the OpenFeign configuration:

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            request-interceptors:
              - com.greenbook.order.interceptor.XTokenRequestInterceptor

3.2 Fallback (Fullback)

When a remote call fails or times out, a fallback implementation can return default data. First add the Sentinel starter dependency:

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

Enable Sentinel for Feign:

feign:
  sentinel:
    enabled: true

Create a fallback class that implements the Feign client interface:

@Service
public class ProductFeignClientFallback implements ProductFeignClient {
    @Override
    public Product getProduct(Long id) {
        log.info("Fallback executed");
        Product product = new Product();
        product.setId(id);
        product.setProductName("Default Product");
        product.setPrice(BigDecimal.ZERO);
        product.setNum(0);
        return product;
    }
}

Reference the fallback in the client declaration:

@FeignClient(value = "service-product", fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {
    @GetMapping("/product/{id}")
    Product getProduct(@PathVariable("id") Long id);
}

Remember to comment out the custom Retryer bean if you want the fallback to trigger after the first failure, because the retry mechanism would otherwise consume all attempts before the fallback is invoked.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavamicroservicesSpring CloudrestOpenFeignFeignClient
Java One
Written by

Java One

Sharing common backend development knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.