Spring Cloud Config позволяет хранить настройки конфигурации сервисов в git-репозитории и управлять настройками централизованно. В этой статье поговорим об обновлении параметров, получаемых с сервера конфигурации. Для работы со свойствами из внешних источников, таких как property-файлы или сервер конфигурации, Spring использует аннотацию PropertySource. А значения свойств можно получать через интерфейс Environment. Как показано на приведенной выше диаграмме, приложение при старте получает источники свойств с сервера конфигурации и помещает их в начало списка доступных источников (PropertySources). Чем выше в этом списке, тем приоритет больше. Источников свойств, на самом деле, больше, чем показано на диаграмме, но, суть в том, что свойства из bootstrap-контекста, обычно приоритетнее локальных property-файлов. После изменения значений в источниках, свойства инжектируются в бины при инстанцировании. Для этого используются аннотации @Value или @ConfigurationProperties. Для обновления свойств в контексте приложения нужно выполнить те же два этапа: обновить источники свойств в Environment и атрибуты бинов. Свойства клиентов Spring Cloud Config Server можно обновить следующими способами: вызовом эндпоинта клиента /actuator/refresh, предоставляемого Spring Actuator; вызовом эндпоинта клиента /actuator/bus-refresh, при интеграции со Spring Cloud Bus; вызовом эндпоинта сервера конфигурации /monitor, интегрированного со Spring Cloud Bus. Эндпоинт /actuator/refresh привязан к клиенту, поэтому обновляется только клиент, к которому будет сделан запрос. На диаграмме ниже показан процесс обновления для этого случая: Например, мы изменяем property-файл и комитим его в git-репозиторий. Далее нам необходимо отразить эти изменения в нашем приложении. Для этого выполняем запрос к /actuator/refresh 3. Этот вызов инициирует обращение клиента к серверу конфигурации и получение последней версии свойств. 4. Далее обновляются источники свойств (PropertySources) в Environment и атрибуты бинов, аннотированных @RefreshScope. 5. Сразу после этого генерируется событие EnvironmentChangeEvent, на которое можно подписаться и обработать при необходимости. В pom.xml нашего клиента добавляем следующую зависимость. По умолчанию большинство эндпоинтов Actuator отключены. Включенные эндпоинты можно посмотреть, обратившись по адресу /actuator. А сделать доступными все, включая /actuator/refresh, следующим образом: Включить эндпоинты выборочно можно, разделив их запятыми: После перезагрузки источников свойств через вызов /actuator/refresh, в бинах с аннотацией @RefreshScope происходит обновление атрибутов с @Value. Для обновления свойств, объявленных с аннотацией @ConfigurationProperties, не требуется @RefreshScope. Также эта аннотация не требуется для получения свойств напрямую из интерфейса Environment. Иногда какой-то параметр конфигурации вычисляется в пост-конструкторе на основе других свойств. В этом случае, помимо обновления атрибута, аннотированного @Value, также необходимо выполнить это вычисление. Это можно сделать, обработав событие EnvironmentChangeEvent, как показано в примере ниже: Для обновления свойств одного клиента вызов эндпоинта refresh прост и удобен. Однако, как правило, сервисов бывает несколько, и ручной вызов этого эндпоинта для каждого из них может быть трудоемким. Один из вариантов решения этой проблемы — автоматизировать процесс с помощью bash-скриптов. Но есть и альтернативное, лучшее решение, предоставляемое еще одним проектом Spring Cloud — Spring Cloud Bus. Spring Cloud Bus позволяет уведомлять сервисы об изменении состояния через брокеры сообщений, такие как Kafka или RabbitMQ. То есть клиенты могут обмениваться информацией через брокер сообщений и обновлять себя в случае изменений конфигурации. Нам не нужно делать запрос на обновление каждого клиента — мы просто отправляем событие обновления через Spring Cloud Bus. Давайте рассмотрим следующую диаграмму: Процесс обновления может быть инициирован вызовом на клиенте /actuator/bus-refresh или /monitor на сервере конфигурации. Сообщение об изменении состояния передается сервисам через брокер сообщений, и каждый сервис при получении события делает запрос к серверу конфигурации. Эндпоинт сервера /monitor предназначен для облачных решений git, таких как Github, для создания push-уведомлений через веб-хуки git. Но можно инициировать событие обновления и вручную, отправив POST-запрос к этому эндпоинту. Мы будем использовать Kafka в качестве брокера сообщений, поэтому добавляем соответствующую зависимость: Для доступности эндпоинта /monitor добавляем на сервере конфигурации, следующую зависимость: И, наконец, настраиваем Spring Cloud Bus и Kafka в bootstrap.properties: Это все, что нужно сделать для подключения сервера конфигурации к брокеру сообщений. Подытожим, что мы сделали: Мы настроили сервер конфигурации на отправку сообщений об изменении состояния через Kafka. На сервере конфигурации настроили эндпоинт /monitor, который отправляет сообщение об изменении состояния через брокер сообщений всем клиентам. Далее настроим клиентскую часть. Мы хотим, чтобы наши сервисы получали сообщения об обновлении конфигурации через брокер сообщений. Для этого в pom.xml клиента также добавляем зависимость Spring Cloud Bus: И аналогично настраиваем Kafka: Теперь наши клиенты готовы к обновлению с помощью Spring Cloud Bus. Мы настроили взаимодействие сервера конфигурации и клиентов через Spring Cloud Bus и обновление с помощью специальных эндпоинтов. Одним из них является bus-refresh, предоставляемый Spring Cloud. Его мы уже настроили. Когда изменяется свойство конфигурации, мы можем просто вызвать /actuator/bus-refresh на любом из клиентов. При этом происходит следующее: Клиент отправляет запрос на сервер конфигурации и обновляет себя. Далее клиент отправляет событие обновления другим сервисам через брокер сообщений. Сервисы, получившие событие обновления, также отправляют запрос на сервер конфигурации для получения актуальных настроек. Обратите внимание, что, в отличие от /actuator/refresh, эндпоинт /actuator/bus-refresh не нужно вызывать для каждого клиента. Есть еще один эндпоинт для обновления конфигурации через Spring Cloud Bus — /monitor. Вот некоторые его особенности: Находится на сервере конфигурации и предоставляется spring-cloud-config-monitor. Предназначен в основном для использования совместно с веб-хуками git и поддерживает облачные решения git, такие как Github и Bitbucket. Инициировать событие обновления можно и вручную. Пришло время эксперимента, давайте запустим пример и посмотрим, что из этого получится. Склонируйте код из Github-репозитория: https://github.com/erolhira/spring-cloud-config  Установите и запустите Kafka. Запустите сервер конфигурации: 4. Проверьте работу сервера конфигурации, введя в браузере следующий адрес. http://localhost:8888/myconfig-client-app/cluster2,instance01/master Вы увидите свойства, полученные из репозитория, который указан в bootstrap.properties: Для изменения свойства создайте свой репозиторий или сделайте копию моего репозитория. 5. Запустите клиента: 6. Проверьте клиента, введя в браузере следующий URL-адрес: http://localhost:8080/config  Вы увидите свойства, полученные с сервера конфигурации в соответствии с профилем и именем приложения в bootstrap.properties. 7. Теперь запустите второй экземпляр клиента на другом порту: 8. Измените значение prop-3 в myconfig-client-app.properties в репозитории. 9. Проверьте работу клиента так же, как в пункте 6. Изменений вы не увидите. 10. Для обновления клиентов вызовите эндпоинт /monitor на сервере конфигурации. 11. Этот вызов заставит сервер конфигурации отправить событие обновления через брокер сообщений. Сообщение, отправляемое через Kafka, выглядит следующим образом: 12. Клиенты получат это сообщение и отправят подтверждение на сервер конфигурации через брокер. Сообщение выглядит следующим образом: 13. Далее клиент обращается к серверу конфигурации и обновляется. 14. Как вы заметили в пункте 11, тип события, отправляемый сервером конфигурации, — RefreshRemoteApplicationEvent. На момент получения клиентом этого события процесс обновления еще не запущен. Поэтому если клиент в обработчике события прочитает свойство конфигурации, то получит старое значение свойства. То есть, в отличие от EnvironmentChangeEvent, мы можем выполнить некоторую предварительную обработку перед обновлением данных конфигурации. Вы также можете увидеть это в приведенном примере. 15. Мы обращались к эндпоинту /monitor вручную, но в реальной жизни, скорее всего, вы будете вызывать его через веб-хуки git при push в репозиторий с конфигурацией. Или, может быть, более подходящим вариантом будет вызов /actuator/bus-refresh клиента. Это уже зависит от вашей конкретной ситуации. Примеры кода вы можете найти в репозитории https://github.com/erolhira/spring-cloud-config https://docs.spring.io/spring-cloud-config/docs/2.2.5.RELEASE/reference/html/https://cloud.spring.io/spring-cloud-static/spring-cloud-bus/2.2.2.RELEASE/reference/html/https://cloud.spring.io/spring-cloud-static/Hoxton.RELEASE/reference/html/spring-cloud-hoxton-configprops.html Материал подготовлен в рамках курса «Разработчик на Spring Framework». Редактор