Remove getEmbeddedServletContainers()
Remove the mutable getEmbeddedServletContainers() Map from EmbeddedWebApplicationContext and instead use the `namespace` to distinguish the management container. The ServerPortInfoApplicationContextInitializer class replaces the previous TestExecutionListener to exposes port properties (by listening for EmbeddedServletContainerInitializedEvents).
This commit is contained in:
		
							parent
							
								
									fad5ce45db
								
							
						
					
					
						commit
						f847ed2b1f
					
				| 
						 | 
				
			
			@ -53,9 +53,7 @@ import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoCo
 | 
			
		|||
import org.springframework.boot.autoconfigure.web.ServerProperties;
 | 
			
		||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContextAware;
 | 
			
		||||
import org.springframework.context.ApplicationListener;
 | 
			
		||||
| 
						 | 
				
			
			@ -173,6 +171,7 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
 | 
			
		|||
 | 
			
		||||
		final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
 | 
			
		||||
		childContext.setParent(this.applicationContext);
 | 
			
		||||
		childContext.setNamespace("management");
 | 
			
		||||
		childContext.setId(this.applicationContext.getId() + ":management");
 | 
			
		||||
 | 
			
		||||
		// Register the ManagementServerChildContextConfiguration first followed
 | 
			
		||||
| 
						 | 
				
			
			@ -197,8 +196,6 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
 | 
			
		|||
		}
 | 
			
		||||
		try {
 | 
			
		||||
			childContext.refresh();
 | 
			
		||||
			registerContainer(this.applicationContext,
 | 
			
		||||
					childContext.getEmbeddedServletContainer());
 | 
			
		||||
		}
 | 
			
		||||
		catch (RuntimeException ex) {
 | 
			
		||||
			// No support currently for deploying a war with management.port=<different>,
 | 
			
		||||
| 
						 | 
				
			
			@ -213,16 +210,6 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
 | 
			
		|||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	private void registerContainer(ApplicationContext applicationContext,
 | 
			
		||||
			EmbeddedServletContainer embeddedServletContainer) {
 | 
			
		||||
		if (applicationContext instanceof EmbeddedWebApplicationContext) {
 | 
			
		||||
			((EmbeddedWebApplicationContext) applicationContext)
 | 
			
		||||
					.getEmbeddedServletContainers().put("management",
 | 
			
		||||
							embeddedServletContainer);
 | 
			
		||||
			// Maybe unregister it when it shuts down?
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected static enum ManagementServerPort {
 | 
			
		||||
 | 
			
		||||
		DISABLE, SAME, DIFFERENT;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.boot.context.embedded;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -29,10 +28,11 @@ import org.springframework.context.ApplicationEvent;
 | 
			
		|||
 */
 | 
			
		||||
public class EmbeddedServletContainerInitializedEvent extends ApplicationEvent {
 | 
			
		||||
 | 
			
		||||
	private final ApplicationContext applicationContext;
 | 
			
		||||
	private final EmbeddedWebApplicationContext applicationContext;
 | 
			
		||||
 | 
			
		||||
	public EmbeddedServletContainerInitializedEvent(
 | 
			
		||||
			ApplicationContext applicationContext, EmbeddedServletContainer source) {
 | 
			
		||||
			EmbeddedWebApplicationContext applicationContext,
 | 
			
		||||
			EmbeddedServletContainer source) {
 | 
			
		||||
		super(source);
 | 
			
		||||
		this.applicationContext = applicationContext;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +60,7 @@ public class EmbeddedServletContainerInitializedEvent extends ApplicationEvent {
 | 
			
		|||
	 * context) before acting on the server container itself.
 | 
			
		||||
	 * @return the applicationContext that the container was created from
 | 
			
		||||
	 */
 | 
			
		||||
	public ApplicationContext getApplicationContext() {
 | 
			
		||||
	public EmbeddedWebApplicationContext getApplicationContext() {
 | 
			
		||||
		return this.applicationContext;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ import java.util.Collection;
 | 
			
		|||
import java.util.Collections;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.EventListener;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
| 
						 | 
				
			
			@ -89,8 +88,6 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
 | 
			
		|||
 */
 | 
			
		||||
public class EmbeddedWebApplicationContext extends GenericWebApplicationContext {
 | 
			
		||||
 | 
			
		||||
	private static final String DEFAULT_SERVER_NAME = "server";
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Constant value for the DispatcherServlet bean name. A Servlet bean with this name
 | 
			
		||||
	 * is deemed to be the "main" servlet and is automatically given a mapping of "/" by
 | 
			
		||||
| 
						 | 
				
			
			@ -105,8 +102,6 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
 | 
			
		|||
 | 
			
		||||
	private String namespace;
 | 
			
		||||
 | 
			
		||||
	private Map<String, EmbeddedServletContainer> containers = new HashMap<String, EmbeddedServletContainer>();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register ServletContextAwareProcessor.
 | 
			
		||||
	 * @see ServletContextAwareProcessor
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +158,6 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
 | 
			
		|||
			EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
 | 
			
		||||
			this.embeddedServletContainer = containerFactory
 | 
			
		||||
					.getEmbeddedServletContainer(getSelfInitializer());
 | 
			
		||||
			this.containers.put(DEFAULT_SERVER_NAME, this.embeddedServletContainer);
 | 
			
		||||
		}
 | 
			
		||||
		else if (getServletContext() != null) {
 | 
			
		||||
			try {
 | 
			
		||||
| 
						 | 
				
			
			@ -388,7 +382,6 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
 | 
			
		|||
			try {
 | 
			
		||||
				this.embeddedServletContainer.stop();
 | 
			
		||||
				this.embeddedServletContainer = null;
 | 
			
		||||
				this.containers.remove(DEFAULT_SERVER_NAME);
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception ex) {
 | 
			
		||||
				throw new IllegalStateException(ex);
 | 
			
		||||
| 
						 | 
				
			
			@ -432,14 +425,4 @@ public class EmbeddedWebApplicationContext extends GenericWebApplicationContext
 | 
			
		|||
		return this.embeddedServletContainer;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * A registry of embedded containers by name. The
 | 
			
		||||
	 * {@link #getEmbeddedServletContainer() canonical container} is called "server".
 | 
			
		||||
	 * Anyone else who creates one can register it with whatever name they please.
 | 
			
		||||
	 * @return the containers
 | 
			
		||||
	 */
 | 
			
		||||
	public Map<String, EmbeddedServletContainer> getEmbeddedServletContainers() {
 | 
			
		||||
		return this.containers;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,53 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2014 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.test;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.test.context.TestContext;
 | 
			
		||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Listener that injects the server port into an {@link Environment} property named
 | 
			
		||||
 * {@literal local.<server>.port}. Useful when the server is running on a dynamic
 | 
			
		||||
 * port.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Dave Syer
 | 
			
		||||
 */
 | 
			
		||||
public class EmbeddedServletContainerTestExecutionListener extends
 | 
			
		||||
		AbstractTestExecutionListener {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void prepareTestInstance(TestContext testContext) throws Exception {
 | 
			
		||||
		ApplicationContext context = testContext.getApplicationContext();
 | 
			
		||||
		if (context instanceof EmbeddedWebApplicationContext) {
 | 
			
		||||
			prepareTestInstance((EmbeddedWebApplicationContext) context);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void prepareTestInstance(EmbeddedWebApplicationContext context) {
 | 
			
		||||
		for (Map.Entry<String, EmbeddedServletContainer> entry : context
 | 
			
		||||
				.getEmbeddedServletContainers().entrySet()) {
 | 
			
		||||
			EnvironmentTestUtils.addEnvironment(context, "local." + entry.getKey()
 | 
			
		||||
					+ ".port:" + entry.getValue().getPort());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,9 +41,7 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi
 | 
			
		|||
@Target(ElementType.TYPE)
 | 
			
		||||
// Leave out the ServletTestExecutionListener because it only deals with Mock* servlet
 | 
			
		||||
// stuff. A real embedded application will not need the mocks.
 | 
			
		||||
@TestExecutionListeners(listeners = {
 | 
			
		||||
		EmbeddedServletContainerTestExecutionListener.class,
 | 
			
		||||
		DependencyInjectionTestExecutionListener.class,
 | 
			
		||||
@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class,
 | 
			
		||||
		DirtiesContextTestExecutionListener.class,
 | 
			
		||||
		TransactionalTestExecutionListener.class })
 | 
			
		||||
public @interface IntegrationTest {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2014 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.test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
 | 
			
		||||
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContextInitializer;
 | 
			
		||||
import org.springframework.context.ApplicationListener;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@link ApplicationContextInitializer} that sets {@link Environment} properties for the
 | 
			
		||||
 * ports that {@link EmbeddedServletContainer} servers are actually listening on. The
 | 
			
		||||
 * property {@literal "local.server.port"} can be injected directly into tests using
 | 
			
		||||
 * {@link Value @Value} or obtained via the {@link Environment}.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * If the {@link EmbeddedWebApplicationContext} has a
 | 
			
		||||
 * {@link EmbeddedWebApplicationContext#setNamespace(String) namespace} set, it will be
 | 
			
		||||
 * used to construct the property name. For example, the "management" actuator context
 | 
			
		||||
 * will have the property name {@literal "local.management.port"}.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Properties are automatically propagated up to any parent context.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Dave Syer
 | 
			
		||||
 * @author Phillip Webb
 | 
			
		||||
 */
 | 
			
		||||
public class ServerPortInfoApplicationContextInitializer implements
 | 
			
		||||
		ApplicationContextInitializer<ConfigurableApplicationContext> {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void initialize(ConfigurableApplicationContext applicationContext) {
 | 
			
		||||
		applicationContext
 | 
			
		||||
				.addApplicationListener(new ApplicationListener<EmbeddedServletContainerInitializedEvent>() {
 | 
			
		||||
					@Override
 | 
			
		||||
					public void onApplicationEvent(
 | 
			
		||||
							EmbeddedServletContainerInitializedEvent event) {
 | 
			
		||||
						ServerPortInfoApplicationContextInitializer.this
 | 
			
		||||
								.onApplicationEvent(event);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
 | 
			
		||||
		String propertyName = getPropertyName(event.getApplicationContext());
 | 
			
		||||
		setPortProperty(event.getApplicationContext(), propertyName, event
 | 
			
		||||
				.getEmbeddedServletContainer().getPort());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected String getPropertyName(EmbeddedWebApplicationContext context) {
 | 
			
		||||
		String name = context.getNamespace();
 | 
			
		||||
		if (StringUtils.isEmpty(name)) {
 | 
			
		||||
			name = "server";
 | 
			
		||||
		}
 | 
			
		||||
		return "local." + name + ".port";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setPortProperty(ApplicationContext context, String propertyName, int port) {
 | 
			
		||||
		if (context instanceof ConfigurableApplicationContext) {
 | 
			
		||||
			EnvironmentTestUtils.addEnvironment((ConfigurableApplicationContext) context,
 | 
			
		||||
					propertyName + ":" + port);
 | 
			
		||||
		}
 | 
			
		||||
		if (context.getParent() != null) {
 | 
			
		||||
			setPortProperty(context.getParent(), propertyName, port);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -174,6 +174,7 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
 | 
			
		|||
	private List<ApplicationContextInitializer<?>> getInitializers(
 | 
			
		||||
			MergedContextConfiguration mergedConfig, SpringApplication application) {
 | 
			
		||||
		List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>();
 | 
			
		||||
		initializers.add(new ServerPortInfoApplicationContextInitializer());
 | 
			
		||||
		initializers.addAll(application.getInitializers());
 | 
			
		||||
		for (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig
 | 
			
		||||
				.getContextInitializerClasses()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue