Rework SpringApplication `sources` property

Update `SpringApplication` so that the `sources` property is
independent to the primary source provided on construction.

Prior to this commit the sources property was a little unusual in that
calling set would add to the existing collection.

Closes gh-8910
pull/7469/merge
Phillip Webb 8 years ago
parent 82b839e4fb
commit 39b33d30e1

@ -80,7 +80,7 @@ import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StandardServletEnvironment; import org.springframework.web.context.support.StandardServletEnvironment;
/** /**
* Classes that can be used to bootstrap and launch a Spring application from a Java main * Class that can be used to bootstrap and launch a Spring application from a Java main
* method. By default class will perform the following steps to bootstrap your * method. By default class will perform the following steps to bootstrap your
* application: * application:
* *
@ -115,9 +115,9 @@ import org.springframework.web.context.support.StandardServletEnvironment;
* *
* <pre class="code"> * <pre class="code">
* public static void main(String[] args) throws Exception { * public static void main(String[] args) throws Exception {
* SpringApplication app = new SpringApplication(MyApplication.class); * SpringApplication application = new SpringApplication(MyApplication.class);
* // ... customize app settings here * // ... customize application settings here
* app.run(args) * application.run(args)
* } * }
* </pre> * </pre>
* *
@ -138,8 +138,8 @@ import org.springframework.web.context.support.StandardServletEnvironment;
* </ul> * </ul>
* *
* Configuration properties are also bound to the {@link SpringApplication}. This makes it * Configuration properties are also bound to the {@link SpringApplication}. This makes it
* possible to set {@link SpringApplication} properties dynamically, like the sources * possible to set {@link SpringApplication} properties dynamically, like additional
* ("spring.main.sources" - a CSV list) the flag to indicate a web environment * sources ("spring.main.sources" - a CSV list) the flag to indicate a web environment
* ("spring.main.web-application-type=none") or the flag to switch off the banner * ("spring.main.web-application-type=none") or the flag to switch off the banner
* ("spring.main.banner-mode=off"). * ("spring.main.banner-mode=off").
* *
@ -215,7 +215,9 @@ public class SpringApplication {
private static final Log logger = LogFactory.getLog(SpringApplication.class); private static final Log logger = LogFactory.getLog(SpringApplication.class);
private final Set<Object> sources = new LinkedHashSet<>(); private final Object[] primarySources;
private Set<Object> additionalSources = new LinkedHashSet<>();
private Class<?> mainApplicationClass; private Class<?> mainApplicationClass;
@ -251,37 +253,38 @@ public class SpringApplication {
/** /**
* Create a new {@link SpringApplication} instance. The application context will load * Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified sources (see {@link SpringApplication class-level} * beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling * documentation for details. The instance can be customized before calling
* {@link #run(String...)}. * {@link #run(String...)}.
* @param sources the bean sources * @param primarySources the primary bean sources
* @see #run(Object, String[]) * @see #run(Object, String[])
* @see #SpringApplication(ResourceLoader, Object...) * @see #SpringApplication(ResourceLoader, Object...)
* @see #setSources(Set)
*/ */
public SpringApplication(Object... sources) { public SpringApplication(Object... primarySources) {
initialize(sources); initialize(primarySources);
this.primarySources = primarySources;
} }
/** /**
* Create a new {@link SpringApplication} instance. The application context will load * Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified sources (see {@link SpringApplication class-level} * beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling * documentation for details. The instance can be customized before calling
* {@link #run(String...)}. * {@link #run(String...)}.
* @param resourceLoader the resource loader to use * @param resourceLoader the resource loader to use
* @param sources the bean sources * @param primarySources the primary bean sources
* @see #run(Object, String[]) * @see #run(Object, String[])
* @see #SpringApplication(ResourceLoader, Object...) * @see #SpringApplication(ResourceLoader, Object...)
* @see #setSources(Set)
*/ */
public SpringApplication(ResourceLoader resourceLoader, Object... sources) { public SpringApplication(ResourceLoader resourceLoader, Object... primarySources) {
this.resourceLoader = resourceLoader; this.resourceLoader = resourceLoader;
initialize(sources); this.primarySources = primarySources;
initialize(primarySources);
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) { private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webApplicationType = deduceWebApplication(); this.webApplicationType = deduceWebApplication();
setInitializers((Collection) getSpringFactoriesInstances( setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class)); ApplicationContextInitializer.class));
@ -395,7 +398,7 @@ public class SpringApplication {
} }
// Load the sources // Load the sources
Set<Object> sources = getSources(); Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty"); Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()])); load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context); listeners.contextLoaded(context);
@ -1130,27 +1133,46 @@ public class SpringApplication {
/** /**
* Returns a mutable set of the sources that will be added to an ApplicationContext * Returns a mutable set of the sources that will be added to an ApplicationContext
* when {@link #run(String...)} is called. * when {@link #run(String...)} is called.
* <p>
* Sources set here will be used in addition to any primary sources set in the
* constructor.
* @return the sources the application sources. * @return the sources the application sources.
* @see #SpringApplication(Object...) * @see #SpringApplication(Object...)
* @see #getAllSources()
*/ */
public Set<Object> getSources() { public Set<Object> getSources() {
return this.sources; return this.additionalSources;
} }
/** /**
* The sources that will be used to create an ApplicationContext. A valid source is * Set additional sources that will be used to create an ApplicationContext. A source
* one of: a class, class name, package, package name, or an XML resource location. * can be: a class, class name, package, package name, or an XML resource location.
* Can also be set using constructors and static convenience methods (e.g.
* {@link #run(Object[], String[])}).
* <p> * <p>
* NOTE: sources defined here will be used in addition to any sources specified on * Sources set here will be used in addition to any primary sources set in the
* construction. * constructor.
* @param sources the sources to set * @param sources the sources to set
* @see #SpringApplication(Object...) * @see #SpringApplication(Object...)
* @see #getAllSources()
*/ */
public void setSources(Set<Object> sources) { public void setSources(Set<Object> sources) {
Assert.notNull(sources, "Sources must not be null"); Assert.notNull(sources, "Sources must not be null");
this.sources.addAll(sources); this.additionalSources = new LinkedHashSet<>(sources);
}
/**
* Return an immutable set of all the sources that will be added to an
* ApplicationContext when {@link #run(String...)} is called. This method combines any
* primary sources specified in the constructor with any additional ones that have
* been {@link #setSources(Set) explicitly set}.
* @return an immutable set of all sources
*/
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!ObjectUtils.isEmpty(this.primarySources)) {
allSources.addAll(Arrays.asList(this.primarySources));
}
allSources.addAll(this.additionalSources);
return Collections.unmodifiableSet(allSources);
} }
/** /**
@ -1246,23 +1268,25 @@ public class SpringApplication {
/** /**
* Static helper that can be used to run a {@link SpringApplication} from the * Static helper that can be used to run a {@link SpringApplication} from the
* specified source using default settings. * specified source using default settings.
* @param source the source to load * @param primarySource the primary source to load
* @param args the application arguments (usually passed from a Java main method) * @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext} * @return the running {@link ApplicationContext}
*/ */
public static ConfigurableApplicationContext run(Object source, String... args) { public static ConfigurableApplicationContext run(Object primarySource,
return run(new Object[] { source }, args); String... args) {
return run(new Object[] { primarySource }, args);
} }
/** /**
* Static helper that can be used to run a {@link SpringApplication} from the * Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments. * specified sources using default settings and user supplied arguments.
* @param sources the sources to load * @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method) * @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext} * @return the running {@link ApplicationContext}
*/ */
public static ConfigurableApplicationContext run(Object[] sources, String[] args) { public static ConfigurableApplicationContext run(Object[] primarySources,
return new SpringApplication(sources).run(args); String[] args) {
return new SpringApplication(primarySources).run(args);
} }
/** /**

@ -580,8 +580,8 @@ public class SpringApplicationTests {
application.setWebApplicationType(WebApplicationType.NONE); application.setWebApplicationType(WebApplicationType.NONE);
application.setUseMockLoader(true); application.setUseMockLoader(true);
this.context = application.run(); this.context = application.run();
Set<Object> initialSources = application.getSources(); Set<Object> allSources = application.getAllSources();
assertThat(initialSources.toArray()).isEqualTo(sources); assertThat(allSources.toArray()).isEqualTo(sources);
} }
@Test @Test

Loading…
Cancel
Save