Загрузить конфигурацию spring программно

#java #spring #microservices

#java #spring #микросервисы

Вопрос:

У меня есть 3 микрослужбы, которые все должны использовать «общую» библиотеку. Мне нужно добавить новую конфигурацию Spring в общую библиотеку. Проблема в том, что микросервису A наплевать на новый код и он не хочет, чтобы его заставляли добавлять конфигурацию для запуска приложения. Мне нужен способ программной загрузки конфигурации только для микросервисов B и C.

Новая конфигурация в общей библиотеке:

 @Configuration
public class HttpConnectionConfiguration {

    @Value("${http.connect.timeout}")
    private int httpConnectTimeout;

    @Value("${http.connect.request.timeout}")
    private int httpConnectRequestTimeout;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        restTemplate.setRequestFactory(getClientHttpRequestFactory());

        return restTemplate;
    }

    private ClientHttpRequestFactory getClientHttpRequestFactory() {
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(httpConnectTimeout)
                .setConnectionRequestTimeout(httpConnectRequestTimeout)
                .build();

        CloseableHttpClient client = HttpClientBuilder
                .create()
                .useSystemProperties()
                .setDefaultRequestConfig(config)
                .build();

        return new HttpComponentsClientHttpRequestFactory(client);
    }
}
  

Конфигурация в микросервисах B и C application.yaml:

 http:
  connect:
    timeout: 5000
    request:
      timeout: 5000
  

Микросервисы B и C запускаются нормально, но A выдает эту ошибку: Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'http.connect.timeout' in value "${http.connect.timeout}

Каков наилучший способ решения этой проблемы без предоставления фиктивных значений в микросервисе A?

Ответ №1:

Решение 1: используйте иерархию конфигурации с дополнительным @Configuration классом, который создает RestTemplate компонент, и активируйте его только для B и C (или когда свойство доступно):

 @Configuration
@ConditionalOnProperty("http.connect.timeout")
public class HttpConnectionConfiguration {

    // rest of code ...
  

Решение 2: используйте значения по умолчанию. Поскольку время ожидания по умолчанию равно -1 , используйте это:

     @Value("${http.connect.timeout:-1}")
    private int httpConnectTimeout;

    @Value("${http.connect.request.timeout:-1}")
    private int httpConnectRequestTimeout;
  

Комментарии:

1. пара вопросов, касающихся решения 1: как вы добавляете несколько ConditionalOnProperty, поскольку есть несколько свойств, которые я, вероятно, должен включить. Кроме того, после включения предложенной аннотации он теперь выдает: ` Метод компонента ‘RestTemplate’ в ‘HttpConnectionConfiguration’ не загружен, потому что @ConditionalOnProperty (http.connect.timeout) не нашел свойство ‘http.connect.timeout»

2. Очевидно, что вам не следует автоматически подключать или иным образом обращаться к компоненту RestTemplate в конфигурации A. Вы можете добиться этого, не создавая экземпляры B и C в конфигурации A (например, выполните более детальное сканирование компонентов).

Ответ №2:

Вы можете указать значения по умолчанию внутри @Value , используя выражение SpEL, подобное приведенному ниже.

 @Value("${http.connect.timeout:10}")
private int httpConnectTimeout;

@Value("${http.connect.request.timeout:10}")
private int httpConnectRequestTimeout;