Add SpringApplicationBuilder

Builder for SpringApplication and ApplicationContext instances with
convenient fluent API and context hierarchy support. Simple example
of a context hierarchy:

   new SpringApplicationBuilder(ParentConfig.class)
               .child(ChildConfig.class).run(args);

Another common use case is setting default arguments, e.g.
active Spring profiles, to set up the environment for an application:

     new SpringApplicationBuilder(Application.class).profiles("server")
 		.defaultArgs("--transport=local").run(args);

If your needs are simpler, consider using the static convenience
methods in SpringApplication instead.

[#49703716] [bs-116] Parent context for some beans maybe?
pull/67/head
Dave Syer 11 years ago
parent 3879afccfb
commit 345c0fc5a4

@ -40,7 +40,7 @@ import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
/**
* Configuration for triggered from {@link EndpointWebMvcAutoConfiguration} when a new
* Configuration triggered from {@link EndpointWebMvcAutoConfiguration} when a new
* {@link EmbeddedServletContainer} running on a different port is required.
*
* @see EndpointWebMvcAutoConfiguration

@ -24,12 +24,11 @@ import java.nio.charset.Charset;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
@ -72,7 +71,7 @@ public class EndpointWebMvcAutoConfigurationTests {
this.applicationContext.register(RootConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
@ -89,7 +88,7 @@ public class EndpointWebMvcAutoConfigurationTests {
this.applicationContext.register(RootConfig.class, DifferentPortConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
@ -106,7 +105,7 @@ public class EndpointWebMvcAutoConfigurationTests {
this.applicationContext.register(RootConfig.class, DisableConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
@ -127,7 +126,8 @@ public class EndpointWebMvcAutoConfigurationTests {
ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class);
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 7070, "controlleroutput");
assertContent("/endpoint", 7070, null);
@ -145,7 +145,8 @@ public class EndpointWebMvcAutoConfigurationTests {
ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class);
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 8080, "controlleroutput");
assertContent("/test/endpoint", 8080, "endpointoutput");

@ -21,9 +21,11 @@ import java.util.Arrays;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
@ -34,8 +36,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.web.servlet.DispatcherServlet;
/**
* {@link EnableAutoConfiguration Auto-configuration} for an the Spring
* {@link DispatcherServlet} servlet containers.
* {@link EnableAutoConfiguration Auto-configuration} for the Spring
* {@link DispatcherServlet} where an embedded servlet container is already present.
*
* @author Phillip Webb
* @author Dave Syer
@ -44,6 +46,7 @@ import org.springframework.web.servlet.DispatcherServlet;
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass(DispatcherServlet.class)
@ConditionalOnBean(EmbeddedServletContainerFactory.class)
@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

@ -22,8 +22,6 @@ import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
@ -68,6 +66,7 @@ public class MultipartAutoConfigurationTests {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNothing.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
@ -86,6 +85,7 @@ public class MultipartAutoConfigurationTests {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNoMultipartJetty.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
@ -114,6 +114,7 @@ public class MultipartAutoConfigurationTests {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNoMultipartTomcat.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
@ -129,6 +130,7 @@ public class MultipartAutoConfigurationTests {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithEverythingJetty.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
this.context.getBean(MultipartConfigElement.class);
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),
@ -141,6 +143,7 @@ public class MultipartAutoConfigurationTests {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithEverythingTomcat.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
this.context.getBean(MultipartConfigElement.class);
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),

@ -27,6 +27,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.sample.tomcat.service.HelloWorldService;
@ -54,7 +55,8 @@ public class NonAutoConfigurationSampleTomcatApplicationTests {
@Configuration
@Import({ EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@ComponentScan(basePackageClasses = { SampleController.class, HelloWorldService.class })
public static class NonAutoConfigurationSampleTomcatApplication {

@ -155,9 +155,7 @@ public class SpringApplication {
private ConfigurableEnvironment environment;
private ApplicationContext applicationContext;
private Class<? extends ApplicationContext> applicationContextClass;
private Class<? extends ConfigurableApplicationContext> applicationContextClass;
private boolean webEnvironment;
@ -245,7 +243,8 @@ public class SpringApplication {
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ApplicationContext run(String... args) {
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
@ -265,18 +264,15 @@ public class SpringApplication {
}
// Create, load, refresh and run the ApplicationContext
ApplicationContext context = createApplicationContext();
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).registerShutdownHook();
((ConfigurableApplicationContext) context).setEnvironment(environment);
}
ConfigurableApplicationContext context = createApplicationContext();
context.registerShutdownHook();
context.setEnvironment(environment);
postProcessApplicationContext(context);
if (context instanceof ConfigurableApplicationContext) {
applyInitializers((ConfigurableApplicationContext) context);
}
applyInitializers(context);
if (this.logStartupInfo) {
logStartupInfo();
}
load(context, sources.toArray(new Object[sources.size()]));
refresh(context);
@ -288,6 +284,7 @@ public class SpringApplication {
runCommandLineRunners(context, args);
return context;
}
private Set<Object> assembleSources() {
@ -310,10 +307,6 @@ public class SpringApplication {
if (this.environment != null) {
return this.environment;
}
if (this.applicationContext != null
&& this.applicationContext.getEnvironment() instanceof ConfigurableEnvironment) {
return (ConfigurableEnvironment) this.applicationContext.getEnvironment();
}
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
@ -398,13 +391,9 @@ public class SpringApplication {
* method will respect any explicitly set application context or application context
* class before falling back to a suitable default.
* @return the application context (not yet refreshed)
* @see #setApplicationContext(ApplicationContext)
* @see #setApplicationContextClass(Class)
*/
protected ApplicationContext createApplicationContext() {
if (this.applicationContext != null) {
return this.applicationContext;
}
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
@ -420,7 +409,8 @@ public class SpringApplication {
}
}
return (ApplicationContext) BeanUtils.instantiate(contextClass);
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
/**
@ -428,7 +418,7 @@ public class SpringApplication {
* apply additional processing as required.
* @param context the application context
*/
protected void postProcessApplicationContext(ApplicationContext context) {
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.webEnvironment) {
if (context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext configurableContext = (ConfigurableWebApplicationContext) context;
@ -477,6 +467,10 @@ public class SpringApplication {
if (context instanceof BeanDefinitionRegistry) {
return (BeanDefinitionRegistry) context;
}
if (context instanceof AbstractApplicationContext) {
return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
.getBeanFactory();
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
@ -628,25 +622,12 @@ public class SpringApplication {
* specified defaults to {@link #DEFAULT_WEB_CONTEXT_CLASS} for web based applications
* or {@link AnnotationConfigApplicationContext} for non web based applications.
* @param applicationContextClass the context class to set
* @see #setApplicationContext(ApplicationContext)
*/
public void setApplicationContextClass(
Class<? extends ApplicationContext> applicationContextClass) {
Class<? extends ConfigurableApplicationContext> applicationContextClass) {
this.applicationContextClass = applicationContextClass;
}
/**
* Sets a Spring {@link ApplicationContext} that will be used for the application. If
* not specified an {@link #DEFAULT_WEB_CONTEXT_CLASS} will be created for web based
* applications or an {@link AnnotationConfigApplicationContext} for non web based
* applications.
* @param applicationContext the spring application context.
* @see #setApplicationContextClass(Class)
*/
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* Sets the {@link ApplicationContextInitializer} that will be applied to the Spring
* {@link ApplicationContext}. Any existing initializers will be replaced.
@ -657,15 +638,6 @@ public class SpringApplication {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>(initializers);
}
/**
* Add {@link ApplicationContextInitializer}s to be applied to the Spring
* {@link ApplicationContext} .
* @param initializers the initializers to add
*/
public void addInitializers(ApplicationContextInitializer<?>... initializers) {
this.initializers.addAll(Arrays.asList(initializers));
}
/**
* Returns a mutable list of the {@link ApplicationContextInitializer}s that will be
* applied to the Spring {@link ApplicationContext}.
@ -682,18 +654,18 @@ public class SpringApplication {
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ApplicationContext run(Object source, String... args) {
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings.
* specified sources using default settings and user supplied arguments.
* @param sources the sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ApplicationContext run(Object[] sources, String[] args) {
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}

@ -0,0 +1,405 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.builder;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.initializer.ParentContextApplicationContextInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
/**
* Builder for {@link SpringApplication} and {@link ApplicationContext} instances with
* convenient fluent API and context hierarchy support. Simple example of a context
* hierarchy:
*
* <pre>
* new SpringApplicationBuilder(ParentConfig.class).child(ChildConfig.class).run(args);
* </pre>
*
* Another common use case is setting default arguments, e.g. active Spring profiles, to
* set up the environment for an application:
*
* <pre>
* new SpringApplicationBuilder(Application.class).profiles(&quot;server&quot;)
* .defaultArgs(&quot;--transport=local&quot;).run(args);
* </pre>
*
* <p>
* If your needs are simpler, consider using the static convenience methods in
* SpringApplication instead.
*
* @author Dave Syer
*
*/
public class SpringApplicationBuilder {
private SpringApplication application;
private ConfigurableApplicationContext context;
private SpringApplicationBuilder parent;
private AtomicBoolean running = new AtomicBoolean(false);
private Set<Object> sources = new LinkedHashSet<Object>();
private String[] defaultArgs;
private ConfigurableEnvironment environment;
public SpringApplicationBuilder(Object... sources) {
this.application = new SpringApplication(sources);
}
/**
* Accessor for the current application context.
*
* @return the current application context (or null if not yet running)
*/
public ConfigurableApplicationContext context() {
return this.context;
}
/**
* Accessor for the current application.
*
* @return the current application (never null)
*/
public SpringApplication application() {
return this.application;
}
/**
* Create an application context (and its parent if specified) with the command line
* args provided. The parent is run first with the same arguments if has not yet been
* started.
*
* @param args the command line arguments
* @return an application context created from the current state
*/
public ConfigurableApplicationContext run(String... args) {
if (this.parent != null) {
// If there is a parent initialize it and make sure it is added to the current
// context
addInitializers(new ParentContextApplicationContextInitializer(
this.parent.run(args)));
}
if (this.running.get()) {
// If already created we just return the existing context
return this.context;
}
if (this.running.compareAndSet(false, true)) {
synchronized (this.running) {
// If not already running copy the sources over and then run.
this.application.setSources(this.sources);
this.context = this.application.run(args);
}
}
return this.context;
}
/**
* Create a child application with the provided sources. Default args and environment
* are copied down into the child, but everything else is a clean sheet.
*
* @param sources the sources for the application (Spring configuration)
* @return the child application nuilder
*/
public SpringApplicationBuilder child(Object... sources) {
SpringApplicationBuilder child = new SpringApplicationBuilder();
child.sources(sources);
// Copy environment stuff from parent to child
child.defaultArgs(this.defaultArgs).environment(this.environment);
child.parent = this;
// It's not possible if embedded containers are enabled to support web contexts as
// parents because the servlets cannot be initialized at the right point in
// lifecycle.
web(false);
// Probably not interested in multiple banners
showBanner(false);
// Make sure sources get copied over
this.application.setSources(this.sources);
return child;
}
/**
* Add a parent application with the provided sources. Default args and environment
* are copied up into the parent, but everything else is a clean sheet.
*
* @param sources the sources for the application (Spring configuration)
* @return the parent builder
*/
public SpringApplicationBuilder parent(Object... sources) {
if (this.parent == null) {
this.parent = new SpringApplicationBuilder(sources).web(false)
.defaultArgs(this.defaultArgs).environment(this.environment);
}
else {
this.parent.sources(sources);
}
return this.parent;
}
private SpringApplicationBuilder runAndExtractParent(String... args) {
if (this.context == null) {
run(args);
}
if (this.parent != null) {
return this.parent;
}
throw new IllegalStateException(
"No parent defined yet (please use the other overloaded parent methods to set one)");
}
/**
* Add an already running parent context to an existing application.
*
* @param parent the parent context
* @return the current builder (not the parent)
*/
public SpringApplicationBuilder parent(ConfigurableApplicationContext parent) {
this.parent = new SpringApplicationBuilder();
this.parent.context = parent;
this.parent.running.set(true);
addInitializers(new ParentContextApplicationContextInitializer(parent));
return this;
}
/**
* Create a sibling application (one with the same parent). A side effect of calling
* this method is that the current application (and its parent) are started.
*
* @param sources the sources for the application (Spring configuration)
*
* @return the new sibling builder
*/
public SpringApplicationBuilder sibling(Object... sources) {
return runAndExtractParent().child(sources);
}
/**
* Create a sibling application (one with the same parent). A side effect of calling
* this method is that the current application (and its parent) are started if they
* are not already running.
*
* @param sources the sources for the application (Spring configuration)
* @param args the command line arguments to use when starting the current app and its
* parent
*
* @return the new sibling builder
*/
public SpringApplicationBuilder sibling(Object[] sources, String... args) {
return runAndExtractParent(args).child(sources);
}
/**
* Explicitly set the context class to be used.
*
* @param cls the context class to use
* @return the current builder
*/
public SpringApplicationBuilder contextClass(
Class<? extends ConfigurableApplicationContext> cls) {
this.application.setApplicationContextClass(cls);
return this;
}
/**
* Add more sources to use in this application.
*
* @param sources the sources to add
* @return the current builder
*/
public SpringApplicationBuilder sources(Object... sources) {
this.sources.addAll(new LinkedHashSet<Object>(Arrays.asList(sources)));
return this;
}
/**
* Add more sources (configuration classes and components) to this application
*
* @param sources the sources to add
* @return the current builder
*/
public SpringApplicationBuilder sources(Class<?>... sources) {
this.sources.addAll(new LinkedHashSet<Object>(Arrays.asList(sources)));
return this;
}
/**
* Flag to explicitly request a web or non-web environment (auto detected based on
* classpath if not set).
*
* @param webEnvironment the flag to set
* @return the current builder
*/
public SpringApplicationBuilder web(boolean webEnvironment) {
this.application.setWebEnvironment(webEnvironment);
return this;
}
/**
* Flag to indicate the startup information should be logged.
*
* @param logStartupInfo the flag to set. Default true.
* @return the current builder
*/
public SpringApplicationBuilder logStartupInfo(boolean logStartupInfo) {
this.application.setLogStartupInfo(logStartupInfo);
return this;
}
/**
* Flag to indicate the startup banner should be printed.
*
* @param showBanner the flag to set. Default true.
* @return the current builder
*/
public SpringApplicationBuilder showBanner(boolean showBanner) {
this.application.setShowBanner(showBanner);
return this;
}
/**
* Fixes the main application class that is used to anchor the startup messages.
*
* @param mainApplicationClass the class to use.
* @return the current builder
*/
public SpringApplicationBuilder main(Class<?> mainApplicationClass) {
this.application.setMainApplicationClass(mainApplicationClass);
return this;
}
/**
* Flag to indicate that command line arguments should be added to the environment.
*
* @param addCommandLineProperties the flag to set. Default true.
* @return the current builder
*/
public SpringApplicationBuilder addCommandLineProperties(
boolean addCommandLineProperties) {
this.application.setAddCommandLineProperties(addCommandLineProperties);
return this;
}
/**
* Default command line arguments (overridden by explicit arguments at runtime in
* {@link #run(String...)}).
*
* @param defaultArgs the args to set.
* @return the current builder
*/
public SpringApplicationBuilder defaultArgs(String... defaultArgs) {
this.defaultArgs = defaultArgs;
this.application.setDefaultArgs(defaultArgs);
if (this.parent != null) {
this.parent.defaultArgs(defaultArgs);
this.parent.environment(this.environment);
}
return this;
}
/**
* Set the active Spring profiles for this app (and its parent and children).
* Synonymous with {@link #defaultArgs(String...)
* defaultArgs("--spring.profiles.active=[profiles]")}
*
* @param profiles the profiles to set.
* @return the current builder
*/
public SpringApplicationBuilder profiles(String... profiles) {
defaultArgs("--spring.profiles.active="
+ StringUtils.arrayToCommaDelimitedString(profiles));
return this;
}
/**
* Bean name generator for automatically generated bean names in the application
* context.
*
* @param beanNameGenerator the generator to set.
* @return the current builder
*/
public SpringApplicationBuilder beanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.application.setBeanNameGenerator(beanNameGenerator);
return this;
}
/**
* Environment for the application context.
*
* @param environment the environment to set.
* @return the current builder
*/
public SpringApplicationBuilder environment(ConfigurableEnvironment environment) {
this.application.setEnvironment(environment);
this.environment = environment;
return this;
}
/**
* {@link ResourceLoader} for the application context. If a custom class loader is
* needed, this is where it would be added.
*
* @param resourceLoader the resource loader to set.
* @return the current builder
*/
public SpringApplicationBuilder resourceLoader(ResourceLoader resourceLoader) {
this.application.setResourceLoader(resourceLoader);
return this;
}
/**
* Add some initializers to the application (applied to the {@link ApplicationContext}
* before any bean definitions are loaded).
*
* @param initializers some initializers to add
* @return the current builder
*/
public SpringApplicationBuilder initializers(
ApplicationContextInitializer<?>... initializers) {
addInitializers(initializers);
return this;
}
/**
* @param initializers the initializers to add
*/
private void addInitializers(ApplicationContextInitializer<?>... initializers) {
Set<ApplicationContextInitializer<?>> target = new LinkedHashSet<ApplicationContextInitializer<?>>(
this.application.getInitializers());
target.addAll(Arrays.asList(initializers));
this.application.setInitializers(target);
}
}

@ -83,6 +83,7 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
* {@link XmlEmbeddedWebApplicationContext} variants.
*
* @author Phillip Webb
* @author Dave Syer
* @see AnnotationConfigEmbeddedWebApplicationContext
* @see XmlEmbeddedWebApplicationContext
* @see EmbeddedServletContainerFactory
@ -146,20 +147,11 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
}
private synchronized void createEmbeddedServletContainer() {
if (this.embeddedServletContainer == null && getServletContext() == null) {
if (this.embeddedServletContainer == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
}
else if (getServletContext() != null) {
try {
getSelfInitializer().onStartup(getServletContext());
}
catch (ServletException ex) {
throw new ApplicationContextException(
"Cannot initialize servlet context", ex);
}
}
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory(),
getServletContext());
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),

@ -49,12 +49,24 @@ import org.springframework.util.StringUtils;
public class ContextIdApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private String name = "${spring.application.name:${vcap.application.name:${spring.config.name:application}}}";
private String name;
private int index = -1;
private int order = Integer.MAX_VALUE - 10;
public ContextIdApplicationContextInitializer() {
this(
"${spring.application.name:${vcap.application.name:${spring.config.name:application}}}");
}
/**
* @param name
*/
public ContextIdApplicationContextInitializer(String name) {
this.name = name;
}
public void setOrder(int order) {
this.order = order;
}

@ -0,0 +1,54 @@
/*
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.context.initializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
/**
* {@link ApplicationContextInitializer} for setting the parent context.
*
* @author Dave Syer
*/
public class ParentContextApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private int order = Integer.MIN_VALUE;
private ApplicationContext parent;
public ParentContextApplicationContextInitializer(ApplicationContext parent) {
this.parent = parent;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setParent(this.parent);
}
}

@ -0,0 +1,58 @@
/*
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.context.initializer;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.Ordered;
import org.springframework.web.context.ConfigurableWebApplicationContext;
/**
* {@link ApplicationContextInitializer} for setting the servlet context.
*
* @author Dave Syer
*/
public class ServletContextApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableWebApplicationContext>, Ordered {
private int order = Integer.MIN_VALUE;
private ServletContext servletContext;
/**
* @param servletContext
*/
public ServletContextApplicationContextInitializer(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public void initialize(ConfigurableWebApplicationContext applicationContext) {
applicationContext.setServletContext(this.servletContext);
}
}

@ -22,8 +22,10 @@ import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.initializer.ParentContextApplicationContextInitializer;
import org.springframework.boot.context.initializer.ServletContextApplicationContextInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ObjectUtils;
import org.springframework.web.WebApplicationInitializer;
@ -77,11 +79,12 @@ public abstract class SpringBootServletInitializer implements WebApplicationInit
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
}
SpringApplication application = new SpringApplication(getConfigClasses());
AnnotationConfigEmbeddedWebApplicationContext context = new AnnotationConfigEmbeddedWebApplicationContext();
context.setParent(parent);
context.setServletContext(servletContext);
application.setApplicationContext(context);
SpringApplicationBuilder application = new SpringApplicationBuilder()
.sources(getConfigClasses());
application.initializers(
new ParentContextApplicationContextInitializer(parent),
new ServletContextApplicationContextInitializer(servletContext));
application.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
return (WebApplicationContext) application.run();
}

@ -0,0 +1,112 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.StaticApplicationContext;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* @author Dave Syer
*/
public class SpringApplicationBuilderTests {
private ConfigurableApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void specificApplicationContextClass() throws Exception {
SpringApplicationBuilder application = new SpringApplicationBuilder().sources(
ExampleConfig.class).contextClass(StaticApplicationContext.class);
this.context = application.run();
assertThat(this.context, is(instanceOf(StaticApplicationContext.class)));
}
@Test
public void parentContextCreation() throws Exception {
SpringApplicationBuilder application = new SpringApplicationBuilder(
ChildConfig.class).contextClass(SpyApplicationContext.class);
application.parent(ExampleConfig.class);
this.context = application.run();
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(
any(ApplicationContext.class));
}
@Test
public void parentFirstCreation() throws Exception {
SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class).child(ChildConfig.class);
application.contextClass(SpyApplicationContext.class);
this.context = application.run();
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(
any(ApplicationContext.class));
}
@Test
public void parentContextIdentical() throws Exception {
SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class);
application.parent(ExampleConfig.class);
application.contextClass(SpyApplicationContext.class);
this.context = application.run();
verify(((SpyApplicationContext) this.context).getApplicationContext()).setParent(
any(ApplicationContext.class));
}
@Configuration
static class ExampleConfig {
}
@Configuration
static class ChildConfig {
}
public static class SpyApplicationContext extends AnnotationConfigApplicationContext {
ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext());
@Override
public void setParent(ApplicationContext parent) {
this.applicationContext.setParent(parent);
}
public ConfigurableApplicationContext getApplicationContext() {
return this.applicationContext;
}
}
}

@ -16,6 +16,7 @@
package org.springframework.boot;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
@ -47,9 +48,7 @@ import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.support.StaticWebApplicationContext;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
@ -74,19 +73,19 @@ public class SpringApplicationTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private ApplicationContext context;
private ConfigurableApplicationContext context;
private Environment getEnvironment() {
if (this.context instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.context).getEnvironment();
if (this.context != null) {
return this.context.getEnvironment();
}
throw new IllegalStateException("No Environment available");
throw new IllegalStateException("Could not obtain Environment");
}
@After
public void close() {
if (this.context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) this.context).close();
if (this.context != null) {
this.context.close();
}
}
@ -121,15 +120,6 @@ public class SpringApplicationTests {
verify(application).printBanner();
}
@Test
public void specificApplicationContext() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class);
ApplicationContext applicationContext = new StaticApplicationContext();
application.setApplicationContext(applicationContext);
this.context = application.run();
assertThat(this.context, sameInstance(applicationContext));
}
@Test
public void specificApplicationContextClass() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class);
@ -144,12 +134,13 @@ public class SpringApplicationTests {
application.setWebEnvironment(false);
final AtomicReference<ApplicationContext> reference = new AtomicReference<ApplicationContext>();
application
.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext context) {
reference.set(context);
}
});
.setInitializers(Arrays
.asList(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext context) {
reference.set(context);
}
}));
this.context = application.run("--foo=bar");
assertThat(this.context, sameInstance(reference.get()));
// Custom initializers do not switch off the defaults
@ -177,12 +168,9 @@ public class SpringApplicationTests {
public void customEnvironment() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class);
application.setWebEnvironment(false);
StaticApplicationContext applicationContext = spy(new StaticApplicationContext());
ConfigurableEnvironment environment = new StandardEnvironment();
application.setApplicationContext(applicationContext);
application.setEnvironment(environment);
application.run();
verify(applicationContext).setEnvironment(environment);
verify(application.getLoader()).setEnvironment(environment);
}
@ -190,12 +178,9 @@ public class SpringApplicationTests {
public void customResourceLoader() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class);
application.setWebEnvironment(false);
StaticApplicationContext applicationContext = spy(new StaticApplicationContext());
ResourceLoader resourceLoader = new DefaultResourceLoader();
application.setApplicationContext(applicationContext);
application.setResourceLoader(resourceLoader);
application.run();
verify(applicationContext).setResourceLoader(resourceLoader);
this.context = application.run();
verify(application.getLoader()).setResourceLoader(resourceLoader);
}
@ -204,22 +189,15 @@ public class SpringApplicationTests {
ResourceLoader resourceLoader = new DefaultResourceLoader();
TestSpringApplication application = new TestSpringApplication(resourceLoader,
ExampleWebConfig.class);
StaticApplicationContext applicationContext = spy(new StaticApplicationContext());
application.setApplicationContext(applicationContext);
application.run();
verify(applicationContext).setResourceLoader(resourceLoader);
this.context = application.run();
verify(application.getLoader()).setResourceLoader(resourceLoader);
applicationContext.close();
}
@Test
public void customBeanNameGenerator() throws Exception {
TestSpringApplication application = new TestSpringApplication(
ExampleWebConfig.class);
StaticWebApplicationContext applicationContext = spy(new StaticWebApplicationContext());
applicationContext.setServletContext(new MockServletContext());
BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
application.setApplicationContext(applicationContext);
application.setBeanNameGenerator(beanNameGenerator);
this.context = application.run();
verify(application.getLoader()).setBeanNameGenerator(beanNameGenerator);
@ -342,10 +320,10 @@ public class SpringApplicationTests {
@Test
public void registerShutdownHook() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class);
ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext());
application.setApplicationContext(applicationContext);
application.run();
verify(applicationContext).registerShutdownHook();
application.setApplicationContextClass(SpyApplicationContext.class);
this.context = application.run();
SpyApplicationContext applicationContext = (SpyApplicationContext) this.context;
verify(applicationContext.getApplicationContext()).registerShutdownHook();
}
private boolean hasPropertySource(ConfigurableEnvironment environment,
@ -363,6 +341,21 @@ public class SpringApplicationTests {
// FIXME test config files?
public static class SpyApplicationContext extends AnnotationConfigApplicationContext {
ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext());
@Override
public void registerShutdownHook() {
this.applicationContext.registerShutdownHook();
}
public ConfigurableApplicationContext getApplicationContext() {
return this.applicationContext;
}
}
private static class TestSpringApplication extends SpringApplication {
private BeanDefinitionLoader loader;

Loading…
Cancel
Save