Commit 43cfebac authored by Scott Frederick's avatar Scott Frederick

Ignore properties files in hidden directories

This commit modifies the logic for finding properties files using
wildcard paths to ignore files if any part of the file path contains
a hidden directory. Hidden directories are common when Kubernetes
mounts config maps onto volumes in a pod, which was causing the same
properties files to be loaded multiple times.

Fixes gh-23160
parent 37cbf1bb
...@@ -18,6 +18,8 @@ package org.springframework.boot.context.config; ...@@ -18,6 +18,8 @@ package org.springframework.boot.context.config;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -108,6 +110,7 @@ import org.springframework.util.StringUtils; ...@@ -108,6 +110,7 @@ import org.springframework.util.StringUtils;
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Madhura Bhave * @author Madhura Bhave
* @author Scott Frederick
* @since 1.0.0 * @since 1.0.0
*/ */
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
...@@ -519,6 +522,14 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, ...@@ -519,6 +522,14 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
continue; continue;
} }
if (resource.isFile() && hasHiddenPathElement(resource)) {
if (this.logger.isTraceEnabled()) {
StringBuilder description = getDescription("Skipped location with hidden path element ",
location, resource, profile);
this.logger.trace(description);
}
continue;
}
String name = "applicationConfig: [" + getLocationName(location, resource) + "]"; String name = "applicationConfig: [" + getLocationName(location, resource) + "]";
List<Document> documents = loadDocuments(loader, name, resource); List<Document> documents = loadDocuments(loader, name, resource);
if (CollectionUtils.isEmpty(documents)) { if (CollectionUtils.isEmpty(documents)) {
...@@ -555,6 +566,16 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, ...@@ -555,6 +566,16 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
} }
} }
private boolean hasHiddenPathElement(Resource resource) throws IOException {
String cleanPath = StringUtils.cleanPath(resource.getFile().getAbsolutePath());
for (Path value : Paths.get(cleanPath)) {
if (value.toString().startsWith(".")) {
return true;
}
}
return false;
}
private String getLocationName(String location, Resource resource) { private String getLocationName(String location, Resource resource) {
if (!location.contains("*")) { if (!location.contains("*")) {
return location; return location;
......
...@@ -75,6 +75,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; ...@@ -75,6 +75,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Dave Syer * @author Dave Syer
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Madhura Bhave * @author Madhura Bhave
* @author Scott Frederick
*/ */
@ExtendWith(OutputCaptureExtension.class) @ExtendWith(OutputCaptureExtension.class)
class ConfigFileApplicationListenerTests { class ConfigFileApplicationListenerTests {
...@@ -1080,6 +1081,16 @@ class ConfigFileApplicationListenerTests { ...@@ -1080,6 +1081,16 @@ class ConfigFileApplicationListenerTests {
assertThat(this.environment.getProperty("third.property")).isNull(); assertThat(this.environment.getProperty("third.property")).isNull();
} }
@Test
void locationsWithWildcardDirectoriesShouldIgnoreHiddenDirectories() {
String location = "file:src/test/resources/config/*/";
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location=" + location);
this.initializer.setSearchNames("testproperties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getProperty("fourth.property")).isNull();
}
@Test @Test
void locationsWithWildcardDirectoriesShouldLoadAllFilesThatMatch() { void locationsWithWildcardDirectoriesShouldLoadAllFilesThatMatch() {
String location = "file:src/test/resources/config/*/"; String location = "file:src/test/resources/config/*/";
...@@ -1124,6 +1135,16 @@ class ConfigFileApplicationListenerTests { ...@@ -1124,6 +1135,16 @@ class ConfigFileApplicationListenerTests {
assertThat(second).isEqualTo("ball"); assertThat(second).isEqualTo("ball");
} }
@Test
void locationsWithWildcardFilesShouldIgnoreHiddenDirectories() {
String location = "file:src/test/resources/config/*/testproperties.properties";
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location=" + location);
this.initializer.setSearchNames("testproperties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getProperty("fourth.property")).isNull();
}
private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) { private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) { return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment