Added wildcard and property placeholder support in SpringApplication

* When a config source is a String it can now be a pattern
* Default resource loaded in the BeanDefinitionLoader has been
changed to PathMatchingResourcePatternResolver;
* A check for the ResourcePatternLoader similar to that in
AbstractBeanDefinitionReader and property placeholder resolution
has been added to the load(CharSequence) method of the
BeanDefinitionLoader;
* Added a unit test illustrating the issue;
pull/50/head
Sergey Shcherbakov 11 years ago committed by Phillip Webb
parent 767aa43e31
commit 0277ce7ab2

@ -16,9 +16,11 @@
package org.springframework.boot; package org.springframework.boot;
import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@ -26,7 +28,6 @@ import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@ -49,7 +50,7 @@ import org.springframework.util.StringUtils;
*/ */
class BeanDefinitionLoader { class BeanDefinitionLoader {
private static final ResourceLoader DEFAULT_RESOURCE_LOADER = new DefaultResourceLoader(); private static final ResourceLoader DEFAULT_RESOURCE_LOADER = new PathMatchingResourcePatternResolver();
private Object[] sources; private Object[] sources;
@ -153,23 +154,51 @@ class BeanDefinitionLoader {
} }
private int load(CharSequence source) { private int load(CharSequence source) {
String sourceString = xmlReader.getEnvironment().resolvePlaceholders(source.toString());
try { try {
// Use class utils so that period separated nested class names work // Use class utils so that period separated nested class names work
return load(ClassUtils.forName(source.toString(), null)); return load(ClassUtils.forName(sourceString, null));
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// swallow exception and continue // swallow exception and continue
} }
Resource loadedResource = (this.resourceLoader != null ? this.resourceLoader ResourceLoader loader = this.resourceLoader != null ?
: DEFAULT_RESOURCE_LOADER).getResource(source.toString()); this.resourceLoader : DEFAULT_RESOURCE_LOADER;
int loadCount = 0;
if( loader instanceof ResourcePatternResolver ) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) loader).getResources(sourceString);
for(Resource resource : resources) {
if( resource.exists() ) {
loadCount += load(resource);
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + sourceString + "]", ex);
}
}
if( !(loader instanceof ResourcePatternResolver) ) {
// Can only load single resources by absolute URL.
Resource loadedResource = loader.getResource(sourceString);
if (loadedResource != null && loadedResource.exists()) { if (loadedResource != null && loadedResource.exists()) {
return load(loadedResource); return load(loadedResource);
} }
}
if( loadCount > 0 ) {
return loadCount;
}
else {
// Attempt to treat the source as a package name, common to all PatternResolver types
Package packageResource = findPackage(source); Package packageResource = findPackage(source);
if (packageResource != null) { if (packageResource != null) {
return load(packageResource); return load(packageResource);
} }
}
throw new IllegalArgumentException("Invalid source '" + source + "'"); throw new IllegalArgumentException("Invalid source '" + source + "'");
} }

@ -276,6 +276,14 @@ public class SpringApplicationTests {
assertThat(initialSources.toArray(), equalTo(sources)); assertThat(initialSources.toArray(), equalTo(sources));
} }
@Test
public void wildcardSources() {
Object[] sources = { "classpath:org/springframework/boot/sample-${sample.app.test.prop}.xml" };
TestSpringApplication application = new TestSpringApplication(sources);
application.setWebEnvironment(false);
application.run();
}
@Test @Test
public void run() throws Exception { public void run() throws Exception {
this.context = SpringApplication.run(ExampleWebConfig.class); this.context = SpringApplication.run(ExampleWebConfig.class);

@ -1 +1,2 @@
foo: bucket foo: bucket
sample.app.test.prop: *
Loading…
Cancel
Save