Multiple Feign Clients in Spring

Multiple Feign Clients in Spring Boot: Configuration and Examples

Spring Cloud OpenFeign makes it easy to call HTTP services through Java interfaces. An application can define multiple Feign clients, each with its own target service, configuration, and request behavior.

This guide shows how to define separate clients, configure them independently, and avoid common issues such as accidentally sharing configuration between clients.

Add the OpenFeign Dependency

For a Spring Boot application using Spring Cloud, add the OpenFeign starter and use a Spring Cloud release train compatible with your Spring Boot version. With Maven, the dependency is typically:

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

Import the Spring Cloud BOM in your build so compatible Spring Cloud dependency versions are managed together. Check the Spring Cloud compatibility guidance for your Spring Boot version rather than selecting versions independently.

Enable Feign Client Scanning

Enable Feign client discovery in your application. By default, Spring scans the package of the application class and its subpackages; specify basePackages if your clients are elsewhere.

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

@SpringBootApplication
@EnableFeignClients(basePackages = "com.example.clients")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Define Multiple Feign Clients

Use a separate interface for each remote service. The name identifies the service, while url can be supplied in configuration for a fixed endpoint.

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

@FeignClient(
        name = "inventory-service",
        url = "${services.inventory.url}"
)
public interface InventoryClient {

    @GetMapping("/api/items/{id}")
    ItemResponse getItem(@PathVariable("id") String id);
}
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(
        name = "billing-service",
        url = "${services.billing.url}"
)
public interface BillingClient {

    @GetMapping("/api/invoices/{id}")
    InvoiceResponse getInvoice(@PathVariable("id") String id);
}

Configure each service URL by environment:

services:
  inventory:
    url: https://inventory.example.com
  billing:
    url: https://billing.example.com

Inject the clients where needed:

import org.springframework.stereotype.Service;

@Service
public class CheckoutService {

    private final InventoryClient inventoryClient;
    private final BillingClient billingClient;

    public CheckoutService(
            InventoryClient inventoryClient,
            BillingClient billingClient) {
        this.inventoryClient = inventoryClient;
        this.billingClient = billingClient;
    }

    public CheckoutSummary checkout(String itemId, String invoiceId) {
        ItemResponse item = inventoryClient.getItem(itemId);
        InvoiceResponse invoice = billingClient.getInvoice(invoiceId);

        return new CheckoutSummary(item, invoice);
    }
}

ItemResponse, InvoiceResponse, and CheckoutSummary represent application-specific data types.

Give Each Client Its Own Configuration

Different services may need different timeouts, authentication headers, logging levels, or error handling. Set a client-specific configuration class in the @FeignClient declaration:

@FeignClient(
        name = "inventory-service",
        url = "${services.inventory.url}",
        configuration = InventoryFeignConfiguration.class
)
public interface InventoryClient {
    // Endpoint declarations
}

A configuration class can provide Feign components. For example, an encoder or decoder can be customized for one client. Exact configuration APIs and property names may vary by Spring Cloud OpenFeign version.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.Logger;

@Configuration
public class InventoryFeignConfiguration {

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
}

Important: Keep client-specific configuration classes outside packages scanned by your main application’s component scan if you do not want their beans applied globally. Alternatively, explicitly control component scanning. A configuration class unintentionally registered in the main application context can affect more clients than intended.

Configure Clients with Properties

Many common client settings can be configured in application properties, including connection and read timeouts. The exact property format depends on the Spring Cloud OpenFeign version. A typical YAML layout is:

spring:
  cloud:
    openfeign:
      client:
        config:
          inventory-service:
            connectTimeout: 2000
            readTimeout: 5000
            loggerLevel: basic
          billing-service:
            connectTimeout: 3000
            readTimeout: 8000
            loggerLevel: basic

Match the configuration key to the Feign client’s configured name or context identifier as required by your version. Consult the documentation for the Spring Cloud release used by your project before relying on a particular property.

Use Different Configuration for Clients with Similar Names

If clients target the same service name but need separate configurations, assign distinct contextId values. This helps Spring distinguish the client contexts:

@FeignClient(
        name = "partner-service",
        contextId = "partnerReadClient",
        url = "${services.partner.url}",
        configuration = PartnerReadConfiguration.class
)
public interface PartnerReadClient {
    // Read operations
}
@FeignClient(
        name = "partner-service",
        contextId = "partnerAdminClient",
        url = "${services.partner.url}",
        configuration = PartnerAdminConfiguration.class
)
public interface PartnerAdminClient {
    // Administrative operations
}

Service Discovery or Fixed URLs

When using service discovery and client-side load balancing, configure the service name and usually omit the fixed url. The service name can then be resolved by the configured discovery and load-balancing integrations.

Use a fixed URL when the endpoint is configured directly, such as for a third-party API or a service whose address is supplied through environment-specific configuration. Avoid hard-coding production endpoints in source code.

Common Issues

  • Feign clients are not detected: Check @EnableFeignClients package scanning and make sure the interfaces are in a scanned package.
  • Two clients conflict: Give clients distinct names or use distinct contextId values when appropriate.
  • One client’s configuration affects others: Ensure client-specific configuration classes are not accidentally picked up by the main application’s component scan.
  • Requests use the wrong URL: Verify the property placeholder and ensure the configured URL matches the intended client.
  • Timeout properties have no effect: Confirm the property names and client key against the documentation for your Spring Cloud OpenFeign version.
  • Calls fail despite a correct client interface: Check DNS, network access, authentication, TLS settings, and the remote service’s response.
  • Compatibility problems after upgrades: Use a Spring Cloud release train compatible with the application’s Spring Boot version.

Multiple Feign Clients FAQ

Can a Spring Boot application have multiple Feign clients?

Yes. Define a separate @FeignClient interface for each remote API and enable scanning for the package containing those interfaces.

Can each Feign client have a different URL?

Yes. Use a distinct URL property for each client, or use service discovery where appropriate.

Can each client use different timeouts or authentication?

Yes. Use client-specific configuration or the supported per-client properties for your Spring Cloud OpenFeign version.

What is contextId used for?

contextId gives a Feign client its own configuration context identity. It is useful when multiple clients share a service name but need separate configurations.

Conclusion

Multiple Feign clients let a Spring application communicate with several HTTP services through clear, injectable interfaces. Define one client per API, configure URLs outside the code, and isolate custom settings when clients need different behavior.

For reliable setup, verify package scanning, keep client-specific configuration from becoming global unintentionally, and use Spring Cloud OpenFeign documentation that matches your Spring Boot and Spring Cloud versions.

Previous Post Next Post

Contact Form