Spring boot : 2.5.6 Spring cloud : 2020.0.4

Hi, I have tried configuring my app to work with both config server and local classpath config file Here is my experience with what works and what does not by trying several configuration formats of spring.config.import

Summary

  1. Only case with application.properties or yaml list format work (see https://github.com/spring-cloud/spring-cloud-config/issues/1849)
  2. yaml set format doesn't works with parsing errors

Conclusion

  • At least I think it might be nice to update the documentation to clarify the working way for setting up import with yaml file only.
  • And in a second time, fix behavior with the set format of spring.config.import in yaml file

Details

Disclaimer : in first place we only use yaml config file. And in all example my config server is deliberately stopped with optional import to generate log even if bootstrap success

1. Failed with yaml config file only, config import with set format and config server at first place

application.yml

spring:
  application:
    name: my-service
  config:
    import: "optional:configserver:", classpath:monitoring.yaml

Result

ERROR - 10:58:29.290 - Saas-DB - [c:|n:] [SpringApplication]: Application run failed org.yaml.snakeyaml.parser.ParserException: while parsing a block mapping in 'reader', line 5, column 5: import: "optional:configserver:" ... ^ expected , but found ',' in 'reader', line 5, column 37: import: "optional:configserver:", classpath:monitoring.yaml

Full stack here
ERROR - 10:58:29.290 - Saas-DB - [c:|n:] [SpringApplication]: Application run failed
org.yaml.snakeyaml.parser.ParserException: while parsing a block mapping
 in 'reader', line 5, column 5:
        import: "optional:configserver:" ... 
        ^
expected <block end>, but found ','
 in 'reader', line 5, column 37:
        import: "optional:configserver:", classpath:monitoring.yaml
    at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:617)
    at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:165)
    at org.yaml.snakeyaml.comments.CommentEventsCollector$1.peek(CommentEventsCollector.java:59)
    at org.yaml.snakeyaml.comments.CommentEventsCollector$1.peek(CommentEventsCollector.java:45)
    at org.yaml.snakeyaml.comments.CommentEventsCollector.collectEvents(CommentEventsCollector.java:140)
    at org.yaml.snakeyaml.comments.CommentEventsCollector.collectEvents(CommentEventsCollector.java:119)
    at org.yaml.snakeyaml.composer.Composer.composeScalarNode(Composer.java:221)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:191)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:313)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:304)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:288)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:195)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:313)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:304)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:288)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:195)
    at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:313)
    at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:304)
    at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:288)
    at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:195)
    at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:115)
    at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:135)
    at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.getData(OriginTrackedYamlLoader.java:99)
    at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:512)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:198)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:166)
    at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:84)
    at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
    at org.springframework.boot.context.config.StandardConfigDataLoader.load(StandardConfigDataLoader.java:54)
    at org.springframework.boot.context.config.StandardConfigDataLoader.load(StandardConfigDataLoader.java:36)
    at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:107)
    at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:128)
    at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
    at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:227)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:374)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:332)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332)
    at com.my.MyServiceApplication.main(MyServiceApplication.java:18)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

2. Failed with yaml config file only, config import with set format and config server at last place

application.yml

spring:
  application:
    name: my-service
  config:
    import: classpath:monitoring.yaml, "optional:configserver:"

Result

ERROR - 11:17:19.034 - Saas-DB - [c:|n:] [SpringApplication]: Application run failed java.lang.IllegalStateException: Unable to load config data from '"optional:configserver:"' Caused by: java.lang.IllegalStateException: File extension is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/' or File.separator

Full stack here
ERROR - 11:17:19.034 - Saas-DB - [c:|n:] [SpringApplication]: Application run failed
java.lang.IllegalStateException: Unable to load config data from '"optional:configserver:"'
    at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:141)
    at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:126)
    at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolve(StandardConfigDataLocationResolver.java:119)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.lambda$resolve$1(ConfigDataLocationResolvers.java:115)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:126)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:115)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:107)
    at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:105)
    at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:97)
    at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:85)
    at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:227)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:374)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:332)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332)
    at com.my.MyServiceApplication.main(MyServiceApplication.java:18)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalStateException: File extension is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/' or File.separator
    at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferencesForFile(StandardConfigDataLocationResolver.java:229)
    at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:138)
    ... 36 common frames omitted

3. Success with config server import extracted in application.properties file

application.yml

spring:
  application:
    name: my-service
  config:
    import: classpath:monitoring.yaml

application.properties

spring.config.import=optional:configserver:

Result

INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: Starting MyServiceApplicationusing Java 11.0.9.1 on ... INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: The following profiles are active: dev WARN - 11:25:56.112 - [c:|n:] [ConfigDataLoader]: Could not locate PropertySource ([ConfigServerConfigDataResource@e090afd uris = array['http://localhost:8888'], optional = true, profiles = list['dev']]): I/O error on GET request for "http://localhost:8888/my-service/dev": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect ... INFO - 11:26:17.743 - [c:|n:] [MyServiceApplication]: Started MyServiceApplicationin 26.415 seconds (JVM running for 29.519)

4. Success with yaml config file only, config import with list format

application.yml

spring:
  application:
    name: my-service
  config:
    import: 
      - classpath:monitoring.yaml
      - "optional:configserver:"

Result

INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: Starting MyServiceApplicationusing Java 11.0.9.1 on ... INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: The following profiles are active: dev WARN - 11:25:56.112 - [c:|n:] [ConfigDataLoader]: Could not locate PropertySource ([ConfigServerConfigDataResource@e090afd uris = array['http://localhost:8888'], optional = true, profiles = list['dev']]): I/O error on GET request for "http://localhost:8888/my-service/dev": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect ... INFO - 11:26:17.743 - [c:|n:] [MyServiceApplication]: Started MyServiceApplicationin 26.415 seconds (JVM running for 29.519)

5. Success with yaml config file only, config import with set format and explicit url

application.yml

spring:
  application:
    name: my-service
  config:
    import: classpath:monitoring.yaml, optional:configserver:http://localhost:8888

or

spring:
  application:
    name: my-service
  config:
    import: optional:configserver:http://localhost:8888, classpath:monitoring.yaml

Please note that, I don't around optional:configserver: with quote else I get the same exception as case 1 and case 2

Result

INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: Starting MyServiceApplicationusing Java 11.0.9.1 on ... INFO - 11:25:56.012 - [c:|n:] [MyServiceApplication]: The following profiles are active: dev WARN - 11:25:56.112 - [c:|n:] [ConfigDataLoader]: Could not locate PropertySource ([ConfigServerConfigDataResource@e090afd uris = array['http://localhost:8888'], optional = true, profiles = list['dev']]): I/O error on GET request for "http://localhost:8888/my-service/dev": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect ... INFO - 11:26:17.743 - [c:|n:] [MyServiceApplication]: Started MyServiceApplicationin 26.415 seconds (JVM running for 29.519)

Comment From: ryanjbaxter

For scenario 1. your YAML is invalid so its a non starter. There should not be any other characters after the closing quote.

For scenario 2, you configuration is invalid. Essentially what you are doing is adding quotes around optional so you are turning optional into "optional:..." and that is not valid. It needs to be optional without any quotes.