Каким образом Spring Cloud Config Server передает обычные текстовые файлы в клиентское приложение Config?
Что я реализовал до сих пор:
- Spring Cloud Config Server с "нативным" репо.
spring.profiles.active: native
spring.cloud.config.server.native.searchLocations: file:/path/to/config-repo
Config Server отправляет уведомление клиентскому приложению Config через RabbitMQ, как http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html
Клиентское приложение Config имеет аннотацию @RefreshScope для компонента EJB.
Итак, / config-repo имеет 3 файла - application.yaml, client.yaml и client.json. Все изменения свойств yaml будут автоматически перезагружены клиентским приложением Config. Однако client.json этого не сделал.
Основываясь на https://github.com/spring-cloud/spring-cloud-config/issues/147, я могу получить файл в клиентском приложении Config через вызов REST API для Config Server с помощью /{appname}/{profile}/{label}/client.json
Вопрос:
1) Config Server отслеживает изменения этого простого текстового файла как "нативный"?
2) как Config Client App автоматически перезагрузить этот client.json после его обновления? (У меня может быть задание по расписанию для вызова сервера Config, но это не идеально.)
2 ответа
Я слоняюсь вот так (еще не закончил): у меня есть spring.cloud.config.server.native.serach-location в виде списка URI через запятую
file:/c:/repo/a,file:/c:/repo/b
Я создал bean-компонент FileMonitorConfiguration (но у него есть некоторые проблемы, потому что он запланирован 2 раза, сам bean-компонент и экземпляр с расширенными возможностями Spring, я не знаком с этим)
И реализовал (просто черновик) NativePropertyPathNotificationExtractor
@Configuration
@EnableAutoConfiguration
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
@Bean
NativePropertyPathNotificationExtractor nativePropertyPathNotificationExtractor(@Autowired(required = false) NativeEnvironmentRepository nativeRepo) {
return new NativePropertyPathNotificationExtractor(nativeRepo);
}
@Bean
FileMonitorConfiguration fileMonitorConfiguration() {
return new FileMonitorConfiguration();
}
}
@Order(Ordered.LOWEST_PRECEDENCE - 500)
public class NativePropertyPathNotificationExtractor implements PropertyPathNotificationExtractor {
private final Set<Path> searchPaths;
public NativePropertyPathNotificationExtractor(NativeEnvironmentRepository nativeRepo) {
searchPaths = searchLocations(nativeRepo);
}
@Override
public PropertyPathNotification extract(MultiValueMap<String, String> headers, Map<String, Object> payload) {
// FileMonitor with empty headers, so if some there, ignore
if (false == headers.isEmpty()) {
return null;
}
if (null == searchPaths) {
return null;
}
Path path = pathFromPayload(payload);
if (null == path) {
return null;
}
for (Path searchPath : searchPaths) {
Path relative = searchPath.relativize(path);
// just a try ;-)
if (true == relative.startsWith("..")) {
continue;
}
return new PropertyPathNotification(relative.toString());
}
return null;
}
private Path pathFromPayload(Map<String, Object> payload) {
if (null == payload) {
return null;
}
if (true == payload.isEmpty()) {
return null;
}
if (false == payload.containsKey("path")) {
return null;
}
if (null == payload.get("path")) {
return null;
}
if (true == StringUtils.isEmpty(payload.get("path").toString())) {
return null;
}
return Paths.get(payload.get("path").toString()).normalize().toAbsolutePath();
}
private Set<Path> searchLocations(NativeEnvironmentRepository nativeRepo) {
if (null == nativeRepo) {
return null;
}
if (null == nativeRepo.getSearchLocations()) {
return null;
}
final Set<Path> paths = new LinkedHashSet<>();
for (String location : nativeRepo.getSearchLocations()) {
try {
paths.add(Paths.get(new URI(location)).normalize().toAbsolutePath());
} catch (Exception e) {
System.err.println("Nevalidne search location uri: " + location);
}
}
return paths;
}
}
Клиент конфигурации: restTemplate.getForObject (" http://localhost:8080/application/default/master/testing-dev.json", String.class);
может получить содержимое файла суффикса.json, но я думаю, что он не получает содержимого файла, есть другой способ получить содержимое файла