Add ServletRegistrationBean for DispatcherServlet

Mapping is exposed via server.servletPath.

Fixes gh-379
This commit is contained in:
Dave Syer 2014-02-20 09:48:51 +00:00
parent 44b877cd7d
commit b2b487ee5f
7 changed files with 147 additions and 84 deletions

View File

@ -39,6 +39,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
@ -71,12 +72,7 @@ public class EndpointWebMvcAutoConfigurationTests {
@Test
public void onSamePort() throws Exception {
this.applicationContext.register(RootConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
this.applicationContext.register(RootConfig.class, BaseConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 8080, "controlleroutput");
@ -90,12 +86,8 @@ public class EndpointWebMvcAutoConfigurationTests {
@Test
public void onDifferentPort() throws Exception {
this.applicationContext.register(RootConfig.class, DifferentPortConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class);
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 8080, "controlleroutput");
assertContent("/endpoint", 8080, null);
@ -108,12 +100,8 @@ public class EndpointWebMvcAutoConfigurationTests {
@Test
public void onRandomPort() throws Exception {
this.applicationContext.register(RootConfig.class, RandomPortConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class);
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class);
GrabManagementPort grabManagementPort = new GrabManagementPort(
this.applicationContext);
this.applicationContext.addApplicationListener(grabManagementPort);
@ -129,12 +117,7 @@ public class EndpointWebMvcAutoConfigurationTests {
@Test
public void disabled() throws Exception {
this.applicationContext.register(RootConfig.class, DisableConfig.class,
PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class);
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 8080, "controlleroutput");
assertContent("/endpoint", 8080, null);
@ -148,13 +131,7 @@ public class EndpointWebMvcAutoConfigurationTests {
public void specificPortsViaProperties() throws Exception {
EnvironmentTestUtils.addEnvironment(this.applicationContext, "server.port:7070",
"management.port:7071");
this.applicationContext.register(RootConfig.class,
PropertyPlaceholderAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
this.applicationContext.register(RootConfig.class, BaseConfiguration.class,
EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class);
this.applicationContext.refresh();
assertContent("/controller", 7070, "controlleroutput");
@ -217,6 +194,17 @@ public class EndpointWebMvcAutoConfigurationTests {
}
}
@Configuration
@Import({ PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class, WebMvcAutoConfiguration.class })
protected static class BaseConfiguration {
}
@Configuration
public static class RootConfig {

View File

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.web;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -26,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
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.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
@ -57,10 +59,24 @@ public class DispatcherServletAutoConfiguration {
*/
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
@Configuration
@Conditional(DefaultDispatcherServletCondition.class)
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
protected static class DispatcherServletConfiguration {
@Autowired
private ServerProperties server;
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public ServletRegistrationBean dispatcherServletRegistration() {
return new ServletRegistrationBean(dispatcherServlet(),
this.server.getServletPath());
}
}
private static class DefaultDispatcherServletCondition extends SpringBootCondition {

View File

@ -56,6 +56,9 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
@NotNull
private String contextPath = "";
@NotNull
private String servletPath = "/";
private final Tomcat tomcat = new Tomcat();
public Tomcat getTomcat() {
@ -70,6 +73,14 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
this.contextPath = contextPath;
}
public String getServletPath() {
return this.servletPath;
}
public void setServletPath(String servletPath) {
this.servletPath = servletPath;
}
public Integer getPort() {
return this.port;
}

View File

@ -0,0 +1,63 @@
/*
* 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.autoconfigure.web;
import org.junit.Test;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author Dave Syer
*/
public class DispatcherServletAutoConfigurationTests {
private AnnotationConfigWebApplicationContext context;
@Test
public void registrationProperties() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(ServerPropertiesAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
assertNotNull(this.context.getBean(DispatcherServlet.class));
ServletRegistrationBean registration = this.context
.getBean(ServletRegistrationBean.class);
assertEquals("[/]", registration.getUrlMappings().toString());
}
@Test
public void servletPath() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(ServerPropertiesAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context, "server.servlet_path:/spring");
this.context.refresh();
assertNotNull(this.context.getBean(DispatcherServlet.class));
ServletRegistrationBean registration = this.context
.getBean(ServletRegistrationBean.class);
assertEquals("[/spring]", registration.getUrlMappings().toString());
}
}

View File

@ -32,6 +32,7 @@ import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFac
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
@ -52,28 +53,21 @@ public class EmbeddedServletContainerAutoConfigurationTests {
@Test
public void createFromConfigClass() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
BaseConfiguration.class);
verifyContext();
}
@Test
public void contextAlreadyHasDispatcherServletWithDefaultName() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
DispatcherServletConfiguration.class,
EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
DispatcherServletConfiguration.class, BaseConfiguration.class);
verifyContext();
}
@Test
public void contextAlreadyHasDispatcherServlet() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
SpringServletConfiguration.class, EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
SpringServletConfiguration.class, BaseConfiguration.class);
verifyContext();
assertEquals(2, this.context.getBeanNamesForType(DispatcherServlet.class).length);
}
@ -81,10 +75,7 @@ public class EmbeddedServletContainerAutoConfigurationTests {
@Test
public void contextAlreadyHasNonDispatcherServlet() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
NonSpringServletConfiguration.class,
EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
NonSpringServletConfiguration.class, BaseConfiguration.class);
verifyContext(); // the non default servlet is still registered
assertEquals(0, this.context.getBeanNamesForType(DispatcherServlet.class).length);
}
@ -92,9 +83,7 @@ public class EmbeddedServletContainerAutoConfigurationTests {
@Test
public void contextAlreadyHasNonServlet() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
NonServletConfiguration.class, EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
NonServletConfiguration.class, BaseConfiguration.class);
assertEquals(0, this.context.getBeanNamesForType(DispatcherServlet.class).length);
assertEquals(0, this.context.getBeanNamesForType(Servlet.class).length);
}
@ -103,9 +92,7 @@ public class EmbeddedServletContainerAutoConfigurationTests {
public void contextAlreadyHasDispatcherServletAndRegistration() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
DispatcherServletWithRegistrationConfiguration.class,
EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
BaseConfiguration.class);
verifyContext();
assertEquals(1, this.context.getBeanNamesForType(DispatcherServlet.class).length);
}
@ -113,20 +100,14 @@ public class EmbeddedServletContainerAutoConfigurationTests {
@Test
public void containerHasNoServletContext() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
EmbeddedContainerConfiguration.class,
EnsureContainerHasNoServletContext.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
EnsureContainerHasNoServletContext.class, BaseConfiguration.class);
verifyContext();
}
@Test
public void customizeContainerThroughCallback() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
EmbeddedContainerConfiguration.class,
CallbackEmbeddedContainerCustomizer.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class);
CallbackEmbeddedContainerCustomizer.class, BaseConfiguration.class);
verifyContext();
assertEquals(9000, getContainerFactory().getPort());
}
@ -144,6 +125,15 @@ public class EmbeddedServletContainerAutoConfigurationTests {
return this.context.getBean(MockEmbeddedServletContainerFactory.class);
}
@Configuration
@Import({ EmbeddedContainerConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class })
protected static class BaseConfiguration {
}
@Configuration
@ConditionalOnExpression("true")
public static class EmbeddedContainerConfiguration {

View File

@ -27,6 +27,7 @@ import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletConta
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@ -64,10 +65,7 @@ public class MultipartAutoConfigurationTests {
@Test
public void containerWithNothing() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNothing.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
ContainerWithNothing.class, BaseConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
assertEquals(0,
@ -83,10 +81,7 @@ public class MultipartAutoConfigurationTests {
@Test
public void containerWithNoMultipartJettyConfiguration() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNoMultipartJetty.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
ContainerWithNoMultipartJetty.class, BaseConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
assertEquals(0,
@ -112,10 +107,7 @@ public class MultipartAutoConfigurationTests {
@Test
public void containerWithNoMultipartTomcatConfiguration() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNoMultipartTomcat.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
ContainerWithNoMultipartTomcat.class, BaseConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
assertNull(servlet.getMultipartResolver());
assertEquals(0,
@ -128,10 +120,7 @@ public class MultipartAutoConfigurationTests {
@Test
public void containerWithAutomatedMultipartJettyConfiguration() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithEverythingJetty.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
ContainerWithEverythingJetty.class, BaseConfiguration.class);
this.context.getBean(MultipartConfigElement.class);
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),
this.context.getBean(StandardServletMultipartResolver.class));
@ -141,10 +130,7 @@ public class MultipartAutoConfigurationTests {
@Test
public void containerWithAutomatedMultipartTomcatConfiguration() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithEverythingTomcat.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
ContainerWithEverythingTomcat.class, BaseConfiguration.class);
new RestTemplate().getForObject("http://localhost:8080/", String.class);
this.context.getBean(MultipartConfigElement.class);
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),
@ -158,6 +144,14 @@ public class MultipartAutoConfigurationTests {
"Hello");
}
@Configuration
@Import({ EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, MultipartAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class })
protected static class BaseConfiguration {
}
@Configuration
public static class ContainerWithNoMultipartTomcat {

View File

@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfigurati
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ -43,7 +44,6 @@ import org.springframework.web.client.RestTemplate;
import sample.tomcat.service.HelloWorldService;
import sample.tomcat.web.SampleController;
import static org.junit.Assert.assertEquals;
/**
@ -57,7 +57,8 @@ public class NonAutoConfigurationSampleTomcatApplicationTests {
@Configuration
@Import({ EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@ComponentScan(basePackageClasses = { SampleController.class, HelloWorldService.class })