Describe the bug
When we add spring.config.import
in application.yml
of an application's src/main/resources
vs the same property is added as -D
parameter during the start up of the application, the behavior changes in terms of property order.
Sample
A test case is added namely ServerMyTestApplicationTests
under spring-cloud-config/spring-cloud-config-sample/src/test/java
(https://github.com/nagsuchandra/spring-cloud-config.git) and it's method contextLoads
shows the issue. There is documentation added to the source file .
Error case: application.yml has the following
spring:
cloud:
config:
uri: http://localhost:${config.port:8888}
config:
import: configserver:${spring.cloud.config.uri}
Now if we run the test ServerMyTestApplicationTests.contextLoads
, the property sources are as follows.
- Config resource 'class path resource [application-baz.yml]' via location 'optional:classpath:/':{key=jarlocal-app-baz-yml}
- configserver:file:././target/repos/configmytest-repo//payroll-baz.yml:{key=remote-payroll-baz-yml}
- configserver:file:././target/repos/configmytest-repo//application-baz.yml:{key=remote-app-baz-yml}
- configserver:file:././target/repos/configmytest-repo//payroll.yml:{key=remote-payroll-yml}
- configserver:file:././target/repos/configmytest-repo//application.yml:{info.foo=bar}
- Config resource 'class path resource [application.yml]' via location 'optional:classpath:/':{info.component=Config Samples, endpoints.restart.enabled=true, logging.levels.org.springframework.boot.env.PropertySourcesLoader=TRACE, logging.levels.org.springframework.web=DEBUG, spring.cloud.config.uri=http://localhost:${config.port:8888}, spring.config.import=configserver:${spring.cloud.config.uri}}
application.yml does NOT have the spring.config.import in there and -Dspring.config.import is passed in
- configserver:file:././target/repos/configmytest-repo//payroll-baz.yml:{key=remote-payroll-baz-yml}
- configserver:file:././target/repos/configmytest-repo//application-baz.yml:{key=remote-app-baz-yml}
- configserver:file:././target/repos/configmytest-repo//payroll.yml:{key=remote-payroll-yml}
- configserver:file:././target/repos/configmytest-repo//application.yml:{info.foo=bar}
- Config resource 'class path resource [application-baz.yml]' via location 'optional:classpath:/':{key=jarlocal-app-baz-yml}
- Config resource 'class path resource [application.yml]' via location 'optional:classpath:/':{info.component=Config Samples, endpoints.restart.enabled=true, logging.levels.org.springframework.boot.env.PropertySourcesLoader=TRACE, logging.levels.org.springframework.web=DEBUG}
Config data files ordering gets reversed if application.yml
has spring.config.import
defined in it , but -D maintains the ordering in the right precedence.
- Application properties packaged inside your jar (application.properties and YAML variants).
- Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
- Application properties outside of your packaged jar (application.properties and YAML variants).
- Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants). – highest priority
Comment From: nagsuchandra
https://github.com/spring-cloud/spring-cloud-config/pull/1839 ( Pull Request link ) The test ServerMyTestApplicationTests.contextLoads shows the issue , comments added.
Comment From: spencergibb
Spring cloud has no control over the precedence anymore, it is controlled by spring boot. IIRC @philwebb and I had a conversation about this and he said this is the working behavior of boot.
Comment From: maggmanu77
@spencergibb , there is no consistency in working behavior of boot then.
i.e.,
1. class path resource [application-baz.yml]
i.e., application-baz.yml
local to jar is given precedence when spring.config.import
is supplied via application.yml local to jar
2. application-baz.yml
from spring cloud config repo gets precedence when spring.config.import
is supplied via system properties
latter is the best fit (abides by spring cloud documentation) logically - which should be made uniform irrespective of how spring.config.import
is supplied.
Comment From: spencergibb
@philwebb will have to talk about that.
Comment From: maggmanu77
@philwebb @spencergibb : this is not a documentation bug (it is incorrectly labelled so).
As illustrated, classpath:application-{profile-name}
(local to jar) is overriding cloud config repo's application-{profile-name}
which is incorrect.
Comment From: spencergibb
@maggmanu77 as I've said, spring cloud can only document this, I can't change the behavior. You'll need to file an issue in spring boot.
Comment From: spencergibb
Something else to consider in the documentation https://github.com/spring-cloud/spring-cloud-config/issues/1807#issuecomment-810579138
Comment From: philwebb
I've pushed something to Spring Boot that will allow imported ConfigData
items to indicate that specific property sources should be considered "profile specific".
Comment From: jhitt25
We started running into this recently when we finally started upgrading Spring Boot, and I believe the issue is slightly more involved than described. We are running on Spring Boot 2.7.4 and Cloud Config Server 2022.0.1 and we are experiencing different results depending on where we run the application from.
Basic setup: Application class files and application.yml
are under /app
Example 1:
Our working directory is /app
and we run java -cp . Main
- spring.config.import
cannot be in application.yml
without breaking precedence (cloud config cannot override any properties specified in application.yml
).
Example 2:
Our working directory is /
and we run java -cp /app Main
- spring.config.import
can safely be included in application.yml
and precedence works as expected (cloud config taking priority over all other settings)
I'm not sure if this is Cloud or Boot, but this is the only issue i still see open, so I started here. Is this something expected, or should I try fleshing out an example to provide?
Edit - further trace logging out of ConfigDataEnvironment makes me think this is definitely a boot issue. It appears that the application.yml is being read twice if it is both in your current directory and also your classpath (java -classpath .
) and this is why spring.config.import
fails to give Cloud Config precedence.