Check Environment matches webEnvironment after it is initialized

After the ApplicationEnvironmentPrepared we now check that the
webEnvironment flag and/or the Environment hasn't changed, in case
the user wanted to switch the context from a web to non-web in a
listener.

Fixes gh-2716
This commit is contained in:
Dave Syer 2015-10-01 17:45:43 +01:00
parent 93d12494e5
commit 2169bbbc9b
2 changed files with 127 additions and 57 deletions

View File

@ -120,7 +120,8 @@ import org.springframework.web.context.support.StandardServletEnvironment;
* your application, however, any of the following sources can also be used: * your application, however, any of the following sources can also be used:
* *
* <ul> * <ul>
* <li>{@link Class} - A Java class to be loaded by {@link AnnotatedBeanDefinitionReader}</li> * <li>{@link Class} - A Java class to be loaded by {@link AnnotatedBeanDefinitionReader}
* </li>
* *
* <li>{@link Resource} - An XML resource to be loaded by {@link XmlBeanDefinitionReader}, * <li>{@link Resource} - An XML resource to be loaded by {@link XmlBeanDefinitionReader},
* or a groovy script to be loaded by {@link GroovyBeanDefinitionReader}</li> * or a groovy script to be loaded by {@link GroovyBeanDefinitionReader}</li>
@ -235,7 +236,8 @@ public class SpringApplication {
this.sources.addAll(Arrays.asList(sources)); this.sources.addAll(Arrays.asList(sources));
} }
this.webEnvironment = deduceWebEnvironment(); this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass(); this.mainApplicationClass = deduceMainApplicationClass();
} }
@ -281,8 +283,8 @@ public class SpringApplication {
context = doRun(listeners, args); context = doRun(listeners, args);
stopWatch.stop(); stopWatch.stop();
if (this.logStartupInfo) { if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted( new StartupInfoLogger(this.mainApplicationClass)
getApplicationLog(), stopWatch); .logStarted(getApplicationLog(), stopWatch);
} }
return context; return context;
} }
@ -312,6 +314,7 @@ public class SpringApplication {
printBanner(environment); printBanner(environment);
} }
environment = resetEnvironment(environment);
// Create, load, refresh and run the ApplicationContext // Create, load, refresh and run the ApplicationContext
context = createApplicationContext(); context = createApplicationContext();
if (this.registerShutdownHook) { if (this.registerShutdownHook) {
@ -348,11 +351,43 @@ public class SpringApplication {
return context; return context;
} }
private ConfigurableEnvironment resetEnvironment(
ConfigurableEnvironment environment) {
if (this.environment != null && environment != this.environment) {
environment = this.environment;
}
if (environment instanceof StandardServletEnvironment && !this.webEnvironment) {
Set<String> servletSources = new HashSet<>(Arrays.asList(
StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME));
ConfigurableEnvironment copy = environment;
environment = new StandardEnvironment();
environment.setActiveProfiles(copy.getActiveProfiles());
String current = null;
MutablePropertySources sources = environment.getPropertySources();
for (PropertySource<?> source : copy.getPropertySources()) {
if (!servletSources.contains(source.getName())) {
String name = source.getName();
if (sources.contains(name)) {
sources.replace(name, source);
}
else if (current == null) {
sources.addFirst(source);
}
else {
sources.addAfter(current, source);
}
current = name;
}
}
}
return environment;
}
private void configureHeadlessProperty() { private void configureHeadlessProperty() {
System.setProperty( System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
Boolean.toString(this.headless)));
} }
private SpringApplicationRunListeners getRunListeners(String[] args) { private SpringApplicationRunListeners getRunListeners(String[] args) {
@ -385,8 +420,8 @@ public class SpringApplication {
instances.add(instance); instances.add(instance);
} }
catch (Throwable ex) { catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " throw new IllegalArgumentException(
+ name, ex); "Cannot instantiate " + type + " : " + name, ex);
} }
} }
@ -416,7 +451,8 @@ public class SpringApplication {
* @see #configureProfiles(ConfigurableEnvironment, String[]) * @see #configureProfiles(ConfigurableEnvironment, String[])
* @see #configurePropertySources(ConfigurableEnvironment, String[]) * @see #configurePropertySources(ConfigurableEnvironment, String[])
*/ */
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
configurePropertySources(environment, args); configurePropertySources(environment, args);
configureProfiles(environment, args); configureProfiles(environment, args);
} }
@ -432,16 +468,16 @@ public class SpringApplication {
String[] args) { String[] args) {
MutablePropertySources sources = environment.getPropertySources(); MutablePropertySources sources = environment.getPropertySources();
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(new MapPropertySource("defaultProperties", sources.addLast(
this.defaultProperties)); new MapPropertySource("defaultProperties", this.defaultProperties));
} }
if (this.addCommandLineProperties && args.length > 0) { if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) { if (sources.contains(name)) {
PropertySource<?> source = sources.get(name); PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name); CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(name composite.addPropertySource(new SimpleCommandLinePropertySource(
+ "-" + args.hashCode(), args)); name + "-" + args.hashCode(), args));
composite.addPropertySource(source); composite.addPropertySource(source);
sources.replace(name, composite); sources.replace(name, composite);
} }
@ -508,14 +544,14 @@ public class SpringApplication {
Class<?> contextClass = this.applicationContextClass; Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) { if (contextClass == null) {
try { try {
contextClass = Class contextClass = Class.forName(this.webEnvironment
.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
: DEFAULT_CONTEXT_CLASS);
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
throw new IllegalStateException( throw new IllegalStateException(
"Unable create a default ApplicationContext, " "Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass", ex); + "please specify an ApplicationContextClass",
ex);
} }
} }
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
@ -544,8 +580,8 @@ public class SpringApplication {
.setResourceLoader(this.resourceLoader); .setResourceLoader(this.resourceLoader);
} }
if (context instanceof DefaultResourceLoader) { if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader ((DefaultResourceLoader) context)
.getClassLoader()); .setClassLoader(this.resourceLoader.getClassLoader());
} }
} }
} }
@ -596,8 +632,8 @@ public class SpringApplication {
*/ */
protected void load(ApplicationContext context, Object[] sources) { protected void load(ApplicationContext context, Object[] sources) {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {
this.log.debug("Loading source " this.log.debug(
+ StringUtils.arrayToCommaDelimitedString(sources)); "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
} }
BeanDefinitionLoader loader = createBeanDefinitionLoader( BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources); getBeanDefinitionRegistry(context), sources);
@ -1018,8 +1054,8 @@ public class SpringApplication {
try { try {
List<ExitCodeGenerator> generators = new ArrayList<ExitCodeGenerator>(); List<ExitCodeGenerator> generators = new ArrayList<ExitCodeGenerator>();
generators.addAll(Arrays.asList(exitCodeGenerators)); generators.addAll(Arrays.asList(exitCodeGenerators));
generators.addAll(context.getBeansOfType(ExitCodeGenerator.class) generators
.values()); .addAll(context.getBeansOfType(ExitCodeGenerator.class).values());
exitCode = getExitCode(generators); exitCode = getExitCode(generators);
} }
finally { finally {

View File

@ -39,6 +39,7 @@ import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEven
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.OutputCapture; import org.springframework.boot.test.OutputCapture;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
@ -64,6 +65,7 @@ import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.context.support.StandardServletEnvironment;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
@ -214,9 +216,8 @@ public class SpringApplicationTests {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
final AtomicReference<ApplicationContext> reference = new AtomicReference<ApplicationContext>(); final AtomicReference<ApplicationContext> reference = new AtomicReference<ApplicationContext>();
application application.setInitializers(Arrays.asList(
.setInitializers(Arrays new ApplicationContextInitializer<ConfigurableApplicationContext>() {
.asList(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override @Override
public void initialize(ConfigurableApplicationContext context) { public void initialize(ConfigurableApplicationContext context) {
reference.set(context); reference.set(context);
@ -233,8 +234,8 @@ public class SpringApplicationTests {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
final AtomicReference<SpringApplication> reference = new AtomicReference<SpringApplication>(); final AtomicReference<SpringApplication> reference = new AtomicReference<SpringApplication>();
class ApplicationReadyEventListener implements class ApplicationReadyEventListener
ApplicationListener<ApplicationReadyEvent> { implements ApplicationListener<ApplicationReadyEvent> {
@Override @Override
public void onApplicationEvent(ApplicationReadyEvent event) { public void onApplicationEvent(ApplicationReadyEvent event) {
reference.set(event.getSpringApplication()); reference.set(event.getSpringApplication());
@ -268,8 +269,8 @@ public class SpringApplicationTests {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
final List<ApplicationEvent> events = new ArrayList<ApplicationEvent>(); final List<ApplicationEvent> events = new ArrayList<ApplicationEvent>();
class ApplicationRunningEventListener implements class ApplicationRunningEventListener
ApplicationListener<ApplicationEvent> { implements ApplicationListener<ApplicationEvent> {
@Override @Override
public void onApplicationEvent(ApplicationEvent event) { public void onApplicationEvent(ApplicationEvent event) {
events.add((event)); events.add((event));
@ -305,7 +306,8 @@ public class SpringApplicationTests {
@Test @Test
public void customEnvironment() throws Exception { public void customEnvironment() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
ConfigurableEnvironment environment = new StandardEnvironment(); ConfigurableEnvironment environment = new StandardEnvironment();
application.setEnvironment(environment); application.setEnvironment(environment);
@ -315,7 +317,8 @@ public class SpringApplicationTests {
@Test @Test
public void customResourceLoader() throws Exception { public void customResourceLoader() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
ResourceLoader resourceLoader = new DefaultResourceLoader(); ResourceLoader resourceLoader = new DefaultResourceLoader();
application.setResourceLoader(resourceLoader); application.setResourceLoader(resourceLoader);
@ -362,9 +365,8 @@ public class SpringApplicationTests {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
ConfigurableEnvironment environment = new StandardEnvironment(); ConfigurableEnvironment environment = new StandardEnvironment();
environment.getPropertySources().addFirst( environment.getPropertySources().addFirst(new MapPropertySource("commandLineArgs",
new MapPropertySource("commandLineArgs", Collections Collections.<String, Object> singletonMap("foo", "original")));
.<String, Object>singletonMap("foo", "original")));
application.setEnvironment(environment); application.setEnvironment(environment);
this.context = application.run("--foo=bar", "--bar=foo"); this.context = application.run("--foo=bar", "--bar=foo");
assertTrue(hasPropertySource(environment, CompositePropertySource.class, assertTrue(hasPropertySource(environment, CompositePropertySource.class,
@ -438,8 +440,8 @@ public class SpringApplicationTests {
ConfigurableEnvironment environment = new StandardEnvironment(); ConfigurableEnvironment environment = new StandardEnvironment();
application.setEnvironment(environment); application.setEnvironment(environment);
this.context = application.run("--foo=bar"); this.context = application.run("--foo=bar");
assertFalse(hasPropertySource(environment, PropertySource.class, assertFalse(
"commandLineArgs")); hasPropertySource(environment, PropertySource.class, "commandLineArgs"));
} }
@Test @Test
@ -465,7 +467,8 @@ public class SpringApplicationTests {
@Test @Test
public void wildcardSources() { public void wildcardSources() {
Object[] sources = { "classpath:org/springframework/boot/sample-${sample.app.test.prop}.xml" }; Object[] sources = {
"classpath:org/springframework/boot/sample-${sample.app.test.prop}.xml" };
TestSpringApplication application = new TestSpringApplication(sources); TestSpringApplication application = new TestSpringApplication(sources);
application.setWebEnvironment(false); application.setWebEnvironment(false);
this.context = application.run(); this.context = application.run();
@ -479,8 +482,8 @@ public class SpringApplicationTests {
@Test @Test
public void runComponents() throws Exception { public void runComponents() throws Exception {
this.context = SpringApplication.run(new Object[] { ExampleWebConfig.class, this.context = SpringApplication.run(
Object.class }, new String[0]); new Object[] { ExampleWebConfig.class, Object.class }, new String[0]);
assertNotNull(this.context); assertNotNull(this.context);
} }
@ -521,7 +524,8 @@ public class SpringApplicationTests {
@Test @Test
public void commandLineArgsApplyToSpringApplication() throws Exception { public void commandLineArgsApplyToSpringApplication() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
this.context = application.run("--spring.main.show_banner=false"); this.context = application.run("--spring.main.show_banner=false");
assertThat(application.getShowBanner(), is(false)); assertThat(application.getShowBanner(), is(false));
@ -582,7 +586,8 @@ public class SpringApplicationTests {
@Test @Test
public void headless() throws Exception { public void headless() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
this.context = application.run(); this.context = application.run();
assertThat(System.getProperty("java.awt.headless"), equalTo("true")); assertThat(System.getProperty("java.awt.headless"), equalTo("true"));
@ -590,7 +595,8 @@ public class SpringApplicationTests {
@Test @Test
public void headlessFalse() throws Exception { public void headlessFalse() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
application.setHeadless(false); application.setHeadless(false);
this.context = application.run(); this.context = application.run();
@ -600,7 +606,8 @@ public class SpringApplicationTests {
@Test @Test
public void headlessSystemPropertyTakesPrecedence() throws Exception { public void headlessSystemPropertyTakesPrecedence() throws Exception {
System.setProperty("java.awt.headless", "false"); System.setProperty("java.awt.headless", "false");
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
this.context = application.run(); this.context = application.run();
assertThat(System.getProperty("java.awt.headless"), equalTo("false")); assertThat(System.getProperty("java.awt.headless"), equalTo("false"));
@ -608,7 +615,8 @@ public class SpringApplicationTests {
@Test @Test
public void getApplicationArgumentsBean() throws Exception { public void getApplicationArgumentsBean() throws Exception {
TestSpringApplication application = new TestSpringApplication(ExampleConfig.class); TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false); application.setWebEnvironment(false);
this.context = application.run("--debug", "spring", "boot"); this.context = application.run("--debug", "spring", "boot");
ApplicationArguments args = this.context.getBean(ApplicationArguments.class); ApplicationArguments args = this.context.getBean(ApplicationArguments.class);
@ -616,6 +624,31 @@ public class SpringApplicationTests {
assertThat(args.containsOption("debug"), equalTo(true)); assertThat(args.containsOption("debug"), equalTo(true));
} }
@Test
public void webEnvironmentSwitchedOffInListener() throws Exception {
TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.addListeners(
new ApplicationListener<ApplicationEnvironmentPreparedEvent>() {
@Override
public void onApplicationEvent(
ApplicationEnvironmentPreparedEvent event) {
assertTrue(event
.getEnvironment() instanceof StandardServletEnvironment);
EnvironmentTestUtils.addEnvironment(event.getEnvironment(),
"foo=bar");
event.getSpringApplication().setWebEnvironment(false);
}
});
this.context = application.run();
assertFalse(this.context.getEnvironment() instanceof StandardServletEnvironment);
assertEquals("bar", this.context.getEnvironment().getProperty("foo"));
assertEquals("test",
this.context.getEnvironment().getPropertySources().iterator().next());
}
private boolean hasPropertySource(ConfigurableEnvironment environment, private boolean hasPropertySource(ConfigurableEnvironment environment,
Class<?> propertySourceClass, String name) { Class<?> propertySourceClass, String name) {
for (PropertySource<?> source : environment.getPropertySources()) { for (PropertySource<?> source : environment.getPropertySources()) {
@ -637,7 +670,8 @@ public class SpringApplicationTests {
public static class SpyApplicationContext extends AnnotationConfigApplicationContext { public static class SpyApplicationContext extends AnnotationConfigApplicationContext {
ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext()); ConfigurableApplicationContext applicationContext = spy(
new AnnotationConfigApplicationContext());
@Override @Override
public void registerShutdownHook() { public void registerShutdownHook() {
@ -784,8 +818,8 @@ public class SpringApplicationTests {
} }
private static class TestCommandLineRunner extends AbstractTestRunner implements private static class TestCommandLineRunner extends AbstractTestRunner
CommandLineRunner { implements CommandLineRunner {
TestCommandLineRunner(int order, String... expectedBefore) { TestCommandLineRunner(int order, String... expectedBefore) {
super(order, expectedBefore); super(order, expectedBefore);
@ -798,8 +832,8 @@ public class SpringApplicationTests {
} }
private static class TestApplicationRunner extends AbstractTestRunner implements private static class TestApplicationRunner extends AbstractTestRunner
ApplicationRunner { implements ApplicationRunner {
TestApplicationRunner(int order, String... expectedBefore) { TestApplicationRunner(int order, String... expectedBefore) {
super(order, expectedBefore); super(order, expectedBefore);