Feign Client
AdvancedFeign is a declarative HTTP client — define an interface annotated with Spring MVC annotations and Feign generates the implementation. Add Resilience4j for circuit breaking and retry to make inter-service calls production-safe.
Overview
In a microservices architecture, services call each other over HTTP. Writing RestTemplate or WebClient code for each call is repetitive and error-prone. Spring Cloud OpenFeign generates a proxy implementation from an annotated interface. Adding @EnableFeignClients scans for @FeignClient interfaces. Combine with Resilience4j for circuit breaking (stop cascading failures) and retry (handle transient errors).
@FeignClient Setup
Add spring-cloud-starter-openfeign. Annotate the interface with @FeignClient specifying the service URL or Eureka service name. Use Spring MVC annotations on the methods — Feign generates the HTTP calls.
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
// Enable Feign on main class or @Configuration
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApp { ... }
// Feign client interface — Feign generates the implementation
@FeignClient(
name = "payment-service",
url = "${services.payment.url:http://payment-service}",
fallbackFactory = PaymentClientFallbackFactory.class
)
public interface PaymentClient {
@PostMapping("/api/v1/payments/charge")
PaymentResponse charge(@RequestBody ChargeRequest request);
@GetMapping("/api/v1/payments/{paymentId}")
PaymentResponse getPayment(@PathVariable String paymentId);
@DeleteMapping("/api/v1/payments/{paymentId}/refund")
RefundResponse refund(@PathVariable String paymentId);
}
// Inject and use exactly like any other Spring bean
@Service
public class OrderService {
private final PaymentClient paymentClient;
public Order placeOrder(PlaceOrderRequest req) {
// Feign handles HTTP, serialization, error mapping
PaymentResponse payment = paymentClient.charge(
new ChargeRequest(req.userId(), req.total(), req.paymentMethod())
);
return createOrder(req, payment.getId());
}
}Fallback, Error Handling and Retry
FallbackFactory creates fallback implementations that receive the exception — return cached data or a default response. Configure timeouts and retries in application.yml.
// Fallback factory — receives the exception causing the fallback
@Component
public class PaymentClientFallbackFactory
implements FallbackFactory<PaymentClient> {
@Override
public PaymentClient create(Throwable cause) {
return new PaymentClient() {
@Override
public PaymentResponse charge(ChargeRequest request) {
log.error("Payment service unavailable: {}", cause.getMessage());
throw new PaymentServiceUnavailableException(
"Payment service is temporarily unavailable");
}
@Override
public PaymentResponse getPayment(String paymentId) {
return PaymentResponse.notAvailable(paymentId);
}
};
}
}
# application.yml — Feign timeouts + Resilience4j circuit breaker
spring:
cloud:
openfeign:
client:
config:
payment-service:
connect-timeout: 2000 # 2s connection timeout
read-timeout: 5000 # 5s read timeout
resilience4j:
circuitbreaker:
instances:
payment-service:
failure-rate-threshold: 50 # open circuit at 50% failures
wait-duration-in-open-state: 30s # wait 30s before trying again
sliding-window-size: 10 # evaluate last 10 calls
retry:
instances:
payment-service:
max-attempts: 3
wait-duration: 500msKey Points to Remember
- 1@EnableFeignClients on your main class triggers scanning for @FeignClient interfaces.
- 2Feign interfaces use Spring MVC annotations (@GetMapping, @RequestBody etc.) — familiar and readable.
- 3FallbackFactory (preferred over Fallback) receives the exception so you can log and handle it properly.
- 4Always configure connect and read timeouts — Feign has no defaults, meaning it can wait forever.
- 5Combine with Resilience4j circuit breaker to stop cascading failures when a downstream service is down.
- 6For async inter-service calls, use WebClient instead of Feign — Feign is synchronous/blocking.
Interview Questions
Sign in to ask AriaWhat is the difference between Feign and RestTemplate?
What is a circuit breaker and why is it important for inter-service calls?
What is the difference between FallbackFactory and a plain Fallback class?
How do you configure a read timeout for a Feign client?
How would you pass authentication headers from the incoming request to a Feign outgoing call?
Ask Aria about Feign Client
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.