Grzegorz Poznachowski
Grzegorz Poznachowski

Reputation: 644

Change FeignClient url at runtime

Having Feign client as presented:

@FeignClient(name = "storeClient", url = "${feign.url}")
public interface StoreClient {
    //..
}

Is is possible to make use of Spring Cloud capabilities of environment changes to change the Feign url at runtime? (Changing the feign.url property and invoking /refresh endpoint)

Upvotes: 7

Views: 9687

Answers (2)

fightlight
fightlight

Reputation: 1055

A bit extended answer with RequestInterceptor:

  1. application.yml
app:
  api-url: http://external.system/messages
  callback-url: http://localhost:8085/callback
  1. @ConfigurationProperties
@Component
@RefreshScope
@ConfigurationProperties("app")
public class AppProperties {
    private String apiUrl;
    private String callbackUrl;
    ...
}
  1. @FeignClient-s configuration

Make sure your ...ClientConfig class is not annotated with any @Component/... annotations or is found by a component scan.

public class ApiClientConfig {
    @Bean
    public RequestInterceptor requestInterceptor(AppProperties appProperties) {
        return requestTemplate -> requestTemplate.target(appProperties.getApiUrl());
    }
}
public class CallbackClientConfig {
    @Bean
    public RequestInterceptor requestInterceptor(AppProperties appProperties) {
        return requestTemplate -> requestTemplate.target(appProperties.getCallbackUrl());
    }
}
  1. @FeignClient-s
@FeignClient(name = "apiClient", url = "NOT_USED", configuration = ApiClientConfig.class)
public interface ApiClient {
    ...
}
@FeignClient(name = "callbackClient", url = "NOT_USED", configuration = CallbackClientConfig.class)
public interface CallbackClient {
    ...
}

Upvotes: 1

Aleksandr Erokhin
Aleksandr Erokhin

Reputation: 1982

As a possible solution - RequestInterceptor could be introduced in order to set URL in RequestTemplate from a property defined in the RefreshScope.

To implement this approach you should do the following:

  1. Define ConfigurationProperties Component in the RefreshScope

    @Component
    @RefreshScope
    @ConfigurationProperties("storeclient")
    public class StoreClientProperties {
        private String url;
        ...
    }
    
  2. Specify default URL for the client in the application.yml

    storeclient
        url: https://someurl
    
  3. Define RequestInterceptor that will switch URL

    @Configuration
    public class StoreClientConfiguration {
    
        @Autowired
        private StoreClientProperties storeClientProperties;
    
        @Bean
        public RequestInterceptor urlInterceptor() {
            return template -> template.insert(0, storeClientProperties.getUrl());
        }
    
    }
    
  4. Use some placeholder in your FeignClient definition for the URL, because it will not be used

    @FeignClient(name = "storeClient", url = "NOT_USED")
    public interface StoreClient {
        //..
    }
    

Now storeclient.url can be refreshed and the URL defined will be used in RequestTemplate to sent http request.

Upvotes: 3

Related Questions