Dynamic Feign Client Configuration in Spring Boot 3: Database‑Driven URLs and Timeouts

This article demonstrates how to externalize Feign client settings—such as base URL, connection and read timeouts, and authentication—into a database, create a factory that builds clients with the latest configuration, and use Spring Cloud OpenFeign together with Actuator to refresh these settings at runtime, complete with full code examples and screenshots.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Dynamic Feign Client Configuration in Spring Boot 3: Database‑Driven URLs and Timeouts

Environment: SpringBoot 3.4.2

1. Introduction

In a micro‑service architecture, Feign is a declarative HTTP client that simplifies inter‑service calls. When the client configuration (base URL, timeouts, authentication) needs to be dynamic, hard‑coding values in application.yml is insufficient.

Typical scenarios requiring dynamic values include:

Multi‑tenant applications where each tenant has a different API endpoint.

Configurations fetched from a database or configuration server.

Routing to different services based on business logic.

This article shows how to configure Feign clients dynamically using a database.

2. Practical Cases

2.1 Define Feign basic configuration entity

@Entity
@Table(name = "t_feign_config")
public class FeignConfig {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    /** client name */
    private String clientName;
    /** base URL */
    private String baseUrl;
    /** request timeout */
    private Long connectTimeout;
    private Long readTimeout;
    private String apiKey;
    // getters, setters
}

2.2 Define Repository interface

public interface FeignConfigRepository extends JpaRepository<FeignConfig, Long> {
    /** Find configuration by client name */
    Optional<FeignConfig> findByClientName(String clientName);
}

2.3 Define Service

@Service
public class FeignConfigService {
    private final FeignConfigRepository configRepository;
    public FeignConfigService(FeignConfigRepository configRepository) {
        this.configRepository = configRepository;
    }
    public FeignConfig getClientConfig(String clientName) {
        return configRepository.findByClientName(clientName)
            .orElseThrow(() -> new RuntimeException("Feign config not found: " + clientName));
    }
}

2.4 Feign client factory

@Component
public class FeignClientFactory {
    private final FeignConfigService configService;
    private final ObjectFactory<HttpMessageConverters> messageConverters;
    public FeignClientFactory(FeignConfigService configService, ObjectFactory<HttpMessageConverters> messageConverters) {
        this.configService = configService;
        this.messageConverters = messageConverters;
    }
    public <T> T getClient(Class<T> clientType, String clientName) {
        FeignConfig config = configService.getClientConfig(clientName);
        Request.Options options = new Request.Options(config.getConnectTimeout(), TimeUnit.MILLISECONDS,
                config.getReadTimeout(), TimeUnit.MILLISECONDS, false);
        return Feign.builder()
            .encoder(new SpringEncoder(this.messageConverters))
            .decoder(new SpringDecoder(messageConverters))
            .contract(new SpringMvcContract())
            .retryer(Retryer.NEVER_RETRY)
            .requestInterceptor(template -> template.header("Authorization", "Bearer " + config.getApiKey()))
            .options(options)
            .target(clientType, config.getBaseUrl());
    }
}

2.5 Test controller

@RestController
@RequestMapping("/test")
public class TestController {
    private final FeignClientFactory factory;
    public TestController(FeignClientFactory factory) {
        this.factory = factory;
    }
    @GetMapping("/user/query")
    public UserDTO query() {
        return this.factory.getClient(UserClient.class, "user-client").query();
    }
}

Calling the above endpoint returns the user data defined in the remote service.

2.6 Dynamically configure request timeout

First, simulate a slow third‑party API:

@GetMapping("/list")
public ResponseEntity<?> list() throws Exception {
    List<User> users = List.of(
        new User("张三", "111111", new Date(), "[email protected]"),
        new User("李四", "222222", new Date(), "[email protected]"),
        new User("王五", "333333", new Date(), "[email protected]"),
        new User("赵六", "444444", new Date(), "[email protected]")
    );
    // Simulate 4‑second delay
    TimeUnit.SECONDS.sleep(4);
    return ResponseEntity.ok(users);
}

Define a Feign interface with a fixed URL:

@FeignClient(name = "user-client", url = "http://localhost:8080")
public interface UserDefaultClient {
    @GetMapping("/users/list")
    List<UserDTO> list();
}

Configure a read timeout of 3 seconds in application.yml:

spring:
  cloud:
    openfeign:
      client:
        config:
          user-client:
            read-timeout: 3000

When the endpoint is called, a timeout exception is thrown because the simulated delay exceeds the configured timeout.

2.7 Dynamically refresh request URL

Remove the url attribute from the Feign annotation and define it in the configuration file:

@FeignClient(name = "user-client")
public interface UserDefaultClient {
    @GetMapping("/users/list")
    List<UserDTO> list();
}
spring:
  cloud:
    openfeign:
      client:
        config:
          user-client:
            url: http://localhost:8080

After starting the service, modify the URL to http://localhost:8081 and invoke the /ac/refresh endpoint provided by Spring Boot Actuator. The new URL takes effect immediately, as shown by the subsequent request results.

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.

feign
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.