diff --git a/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java index 3e2ff2fb4f5e..b39db056b995 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java @@ -234,6 +234,14 @@ void multipleComposedPropertySourceAnnotations() { // gh-30941 ctx.close(); } + @Test + void multipleResourcesFromPropertySourcePattern() { // gh-21325 + ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(ResourcePatternConfig.class); + ctx.getBean(ResourcePatternConfig.class); + assertEnvironmentContainsProperties(ctx, "from.p1", "from.p2", "from.p3", "from.p4", "from.p5"); + ctx.close(); + } + @Test void withNamedPropertySources() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNamedPropertySources.class); @@ -277,15 +285,15 @@ void orderingWithAndWithoutNameAndMultipleResourceLocations() { } @Test - void orderingWithAndWithoutNameAndFourResourceLocations() { + void orderingWithFourResourceLocations() { // SPR-12198: p4 should 'win' as it was registered last - AnnotationConfigApplicationContext ctxWithoutName = new AnnotationConfigApplicationContext(ConfigWithFourResourceLocations.class); - assertEnvironmentProperty(ctxWithoutName, "testbean.name", "p4TestBean"); - ctxWithoutName.close(); + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithFourResourceLocations.class); + assertEnvironmentProperty(ctx, "testbean.name", "p4TestBean"); + ctx.close(); } @Test - void orderingDoesntReplaceExisting() throws Exception { + void orderingDoesntReplaceExisting() { // SPR-12198: mySource should 'win' as it was registered manually AnnotationConfigApplicationContext ctxWithoutName = new AnnotationConfigApplicationContext(); MapPropertySource mySource = new MapPropertySource("mine", Map.of("testbean.name", "myTestBean")); @@ -522,6 +530,12 @@ static class ConfigWithRepeatedPropertySourceAnnotationsOnComposedAnnotation { static class MultipleComposedAnnotationsConfig { } + + @PropertySource("classpath*:org/springframework/context/annotation/p?.properties") + static class ResourcePatternConfig { + } + + @Configuration @PropertySources({ @PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"), diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PropertySourceProcessor.java b/spring-core/src/main/java/org/springframework/core/io/support/PropertySourceProcessor.java index 407c5019e71d..b226fdf42e3f 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PropertySourceProcessor.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PropertySourceProcessor.java @@ -46,6 +46,7 @@ * * @author Stephane Nicoll * @author Sam Brannen + * @author Juergen Hoeller * @since 6.0 * @see PropertySourceDescriptor */ @@ -58,14 +59,14 @@ public class PropertySourceProcessor { private final ConfigurableEnvironment environment; - private final ResourceLoader resourceLoader; + private final ResourcePatternResolver resourcePatternResolver; private final List propertySourceNames = new ArrayList<>(); public PropertySourceProcessor(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { this.environment = environment; - this.resourceLoader = resourceLoader; + this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); } @@ -87,8 +88,9 @@ public void processPropertySource(PropertySourceDescriptor descriptor) throws IO for (String location : locations) { try { String resolvedLocation = this.environment.resolveRequiredPlaceholders(location); - Resource resource = this.resourceLoader.getResource(resolvedLocation); - addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding))); + for (Resource resource : this.resourcePatternResolver.getResources(resolvedLocation)) { + addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding))); + } } catch (RuntimeException | IOException ex) { // Placeholders not resolvable (IllegalArgumentException) or resource not found when trying to open it