Describe the bug

After I upgraded spring cloud config server from version 2.3.10 to 2.4.5 the order in which properties files are processed changed. Before the upgrade properties from profile specific files, e.g. {application}-{profile}.properties, had precedence over general files like {application}.properties, and after the upgrade it is the opposite.

I am using cloud config server with spring.cloud.config.server.git.searchPaths option set to '**' so that I can have properties files structured in directories, like this:

  • dir1/{application}.properties
  • dir1/dir2/{application}-{profile}.properties

I also checked this with v2.4.7-SNAPSHOT and it is the same there

Sample

I created a simple cloud config server based on https://start.spring.io/ code generated . Set the content of application.properties to

spring.cloud.config.server.git.uri: https://github.com/grabarczyk-t/cloud-config-test.git
spring.cloud.config.server.git.searchPaths: '**'

In the git repository I have two property files:

  • project/application.properties
  • project/test/application-test.properties

both with just one property sample.property, with different value in each file. When I run the server locally and make request to http://localhost:8080/application/test I get:

In the 2.3.10 version:

{"name":"application","profiles":["test"],"label":null,"version":"32248076b1c298d26c0f4afc9f6464f0e452e18f","state":null,"propertySources":[{"name":"https://github.com/grabarczyk-t/cloud-config-test.git/project/test/application-test.properties","source":{"sample.property":"value from application-test.properties"}},{"name":"https://github.com/grabarczyk-t/cloud-config-test.git/project/application.properties","source":{"sample.property":"value from application.properties"}}]}

In the 2.4.5 version:

{"name":"application","profiles":["test"],"label":null,"version":"32248076b1c298d26c0f4afc9f6464f0e452e18f","state":null,"propertySources":[{"name":"https://github.com/grabarczyk-t/cloud-config-test.git/file:C:\\Users\\Tom\\AppData\\Local\\Temp\\config-repo-14384905862201453365\\project\\application.properties","source":{"sample.property":"value from application.properties"}},{"name":"https://github.com/grabarczyk-t/cloud-config-test.git/file:C:\\Users\\Tom\\AppData\\Local\\Temp\\config-repo-14384905862201453365\\project\\test\\application-test.properties","source":{"sample.property":"value from application-test.properties"}}]}

I also checked it with a simple cloud config client application. I have profile set to test (spring.profiles.include=test), and when I check the value of this property using @Value:

@Value("${sample.property}") private String sampleProperty;

the sampleProperty has the value from application-test.properties when the 2.3.10 config server is running, and value from the application.properties when the 2.4.5 config server is running

Comment From: ryanjbaxter

Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

Comment From: grabarczyk-t

Yes, sure. I uploaded zip file with code that reproduces this problem. After unzipping the file enter the CloudConfigServer directory and run mvnw spring-boot:run, this will run cloud config server. Then do:

curl http://localhost:8080/application/test

this will return similar output that I described in the issue description, and it shows that the propertySources are in wrong order - property source for application.properties file is before property source for application-test.properties file and it should be the other way around

CloudConfigServer.zip

Comment From: ryanjbaxter

I think this is due to the way Spring Boot is ordering property sources and profile specific property sources not taking precedence. See https://github.com/spring-projects/spring-boot/issues/26593

Comment From: philwebb

I've applied a change that should fix https://github.com/spring-projects/spring-boot/issues/26593 but we'll probably also need a change in Spring Cloud. The ordering change was actually intentional (see https://github.com/spring-projects/spring-boot/issues/3845) but we overlooked that as well as inside and outside the jar we also have ./ and ./config to consider. To deal with that I've update the code so that a spring.config.location entry can contain multiple files or directories. Spring Boot now uses the following:

optional:classpath:/;optional:classpath:/config/,optional:file:./;optional:file:./config/;optional:file:./config/*/

This is defining two location groups (one for the classpath in the jar and one for files outside of the jar). The groups themselves define the actual locations.

I suspect that this part of the code will need to change to build the correct location string. Perhaps replacing arrayToCommaDelimitedString(...) with delimitedListToStringArray(..., ";")?

Comment From: ryanjbaxter

Thanks @philwebb. Yeah that is one place that we need to change. But also this logic is no longer valid

https://github.com/spring-cloud/spring-cloud-config/blob/b1e795d8d191c04d1221ab88a30a6b2f431bba7f/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/NativeEnvironmentRepository.java#L256

A ConfigDataLocation now contains a list of locations instead of just a single location. Probably need to wrap that logic in a loop of some kind. I see ConfigDataLocation now has a split method to get an array delimited by ;, I can probably use that.

I plan on looking at this more tomorrow.