Provide seamless support for local.server.port

Previously, the actual HTTP port on which a web application is running on
was only exposed in tests. This commit makes sure to provide that feature
regardless of the environment so that applications can know on which port
they are actually running on.

If there are several containers, each is exposed via the namespace of
their respective application context.

Closes gh-3259
pull/2592/merge
Stephane Nicoll 10 years ago
parent cb98ee25ff
commit c177a774a5

@ -50,8 +50,8 @@ import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebAppl
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.ServerPortInfoApplicationContextInitializer;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;

@ -400,6 +400,9 @@ code.
=== Use a random unassigned HTTP port === Use a random unassigned HTTP port
To scan for a free port (using OS natives to prevent clashes) use `server.port=0`. To scan for a free port (using OS natives to prevent clashes) use `server.port=0`.
TIP: You can know what port got allocated at runtime by looking at the `local.server.port`
property in the `Environment`.
[[howto-discover-the-http-port-at-runtime]] [[howto-discover-the-http-port-at-runtime]]

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,7 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.test; package org.springframework.boot.context.web;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainer;
@ -24,7 +27,10 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -75,8 +81,21 @@ public class ServerPortInfoApplicationContextInitializer implements
private void setPortProperty(ApplicationContext context, String propertyName, int port) { private void setPortProperty(ApplicationContext context, String propertyName, int port) {
if (context instanceof ConfigurableApplicationContext) { if (context instanceof ConfigurableApplicationContext) {
EnvironmentTestUtils.addEnvironment((ConfigurableApplicationContext) context, ConfigurableEnvironment environment = ((ConfigurableApplicationContext) context).getEnvironment();
propertyName + ":" + port); MutablePropertySources sources = environment.getPropertySources();
Map<String, Object> map;
if (!sources.contains("server.ports")) {
map = new HashMap<String, Object>();
MapPropertySource source = new MapPropertySource("server.ports", map);
sources.addFirst(source);
}
else {
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) sources.get("server.ports")
.getSource();
map = value;
}
map.put(propertyName, port);
} }
if (context.getParent() != null) { if (context.getParent() != null) {
setPortProperty(context.getParent(), propertyName, port); setPortProperty(context.getParent(), propertyName, port);

@ -198,7 +198,6 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>(); List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>();
initializers.add(new PropertySourceLocationsInitializer(mergedConfig initializers.add(new PropertySourceLocationsInitializer(mergedConfig
.getPropertySourceLocations())); .getPropertySourceLocations()));
initializers.add(new ServerPortInfoApplicationContextInitializer());
initializers.addAll(application.getInitializers()); initializers.addAll(application.getInitializers());
for (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig for (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig
.getContextInitializerClasses()) { .getContextInitializerClasses()) {

@ -11,7 +11,8 @@ org.springframework.boot.context.event.EventPublishingRunListener
org.springframework.context.ApplicationContextInitializer=\ org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
# Application Listeners # Application Listeners
org.springframework.context.ApplicationListener=\ org.springframework.context.ApplicationListener=\

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -239,7 +239,7 @@ public class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder( SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class).web(false); ExampleConfig.class).web(false);
this.context = application.run(); this.context = application.run();
assertEquals(3, application.application().getInitializers().size()); assertEquals(4, application.application().getInitializers().size());
} }
@Test @Test
@ -247,7 +247,7 @@ public class SpringApplicationBuilderTests {
SpringApplicationBuilder application = new SpringApplicationBuilder( SpringApplicationBuilder application = new SpringApplicationBuilder(
ExampleConfig.class).child(ChildConfig.class).web(false); ExampleConfig.class).child(ChildConfig.class).web(false);
this.context = application.run(); this.context = application.run();
assertEquals(4, application.application().getInitializers().size()); assertEquals(5, application.application().getInitializers().size());
} }
@Test @Test
@ -261,7 +261,7 @@ public class SpringApplicationBuilderTests {
} }
}); });
this.context = application.run(); this.context = application.run();
assertEquals(4, application.application().getInitializers().size()); assertEquals(5, application.application().getInitializers().size());
} }
@Configuration @Configuration

@ -41,6 +41,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.Scope; import org.springframework.beans.factory.config.Scope;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer;
import org.springframework.context.ApplicationContextException; import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.AbstractApplicationContext;
@ -73,6 +74,7 @@ import static org.mockito.Mockito.withSettings;
* Tests for {@link EmbeddedWebApplicationContext}. * Tests for {@link EmbeddedWebApplicationContext}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
*/ */
public class EmbeddedWebApplicationContextTests { public class EmbeddedWebApplicationContextTests {
@ -144,6 +146,15 @@ public class EmbeddedWebApplicationContextTests {
assertEquals(this.context, event.getApplicationContext()); assertEquals(this.context, event.getApplicationContext());
} }
@Test
public void localPortIsAvailable() throws Exception {
addEmbeddedServletContainerFactoryBean();
new ServerPortInfoApplicationContextInitializer().initialize(this.context);
this.context.refresh();
assertTrue(this.context.getEnvironment().containsProperty("local.server.port"));
assertEquals("8080", this.context.getEnvironment().getProperty("local.server.port"));
}
@Test @Test
public void stopOnClose() throws Exception { public void stopOnClose() throws Exception {
addEmbeddedServletContainerFactoryBean(); addEmbeddedServletContainerFactoryBean();

Loading…
Cancel
Save