1
votes

What I have implemented so far are:

  1. Spring Cloud Config Server with "native" repo.

spring.profiles.active: native

spring.cloud.config.server.native.searchLocations: file:/path/to/config-repo

  1. Config Server is pushing notification to Config Client App through RabbitMQ, as http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_push_notifications_and_spring_cloud_bus

  2. Config Client App has @RefreshScope annotated on Service bean.

So /config-repo has 3 files - application.yaml, client.yaml and client.json All yaml properties changes will be auto reloaded by Config Client App for sure. However, client.json didn't.

Based on https://github.com/spring-cloud/spring-cloud-config/issues/147, I can fetch the file on Config Client App through REST api call to Config Server, with /{appname}/{profile}/{label}/client.json

Question are:

1) Is Config Server monitoring this plain text file changes by "native"?

2) how can Config Client App auto reload this client.json once it's updated? (I can have schedule task to call Config server, but this isn't ideal.)

2
Hi, I am wondering if you run into this issue: github.com/spring-cloud/spring-cloud-config/issues/546Ilayaperumal Gopinathan
I have followed this instruction. But it's not working with plain text file.Cuizhanming

2 Answers

1
votes

i am sloving like this way (not finnished yet): i have spring.cloud.config.server.native.serach-locations in form of comma separated list of URIs

file:/c:/repo/a,file:/c:/repo/b

I created FileMonitorConfiguration bean (but it have some problem, because it is scheduled 2 times, a bean itself and a spring enhaced instance, I am not fammiliar with this)

And implemented (just draft) 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;

    }
}
1
votes

the Config client: restTemplate.getForObject("http://localhost:8080/application/default/master/testing-dev.json",String.class);

can get the .json suffix file content ,but i think it don't get the file content ,have other way to get the file content