diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java index 933adcce045..dfc475b4bb5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; @@ -110,12 +111,6 @@ public class DispatcherServletAutoConfiguration { return resolver; } - @Bean - public DispatcherServletPathProvider mainDispatcherServletPathProvider() { - return () -> DispatcherServletConfiguration.this.webMvcProperties.getServlet() - .getPath(); - } - } @Configuration @@ -152,6 +147,14 @@ public class DispatcherServletAutoConfiguration { return registration; } + @Bean + @ConditionalOnMissingBean(DispatcherServletPathProvider.class) + @ConditionalOnSingleCandidate(DispatcherServlet.class) + public DispatcherServletPathProvider dispatcherServletPathProvider() { + return () -> DispatcherServletRegistrationConfiguration.this.webMvcProperties + .getServlet().getPath(); + } + } @Order(Ordered.LOWEST_PRECEDENCE - 10) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java index 0c9b3064cd6..af000e0ce0f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java @@ -35,6 +35,7 @@ import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.servlet.DispatcherServlet; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link DispatcherServletAutoConfiguration}. @@ -65,6 +66,8 @@ public class DispatcherServletAutoConfigurationTests { .run((context) -> { assertThat(context).doesNotHaveBean(ServletRegistrationBean.class); assertThat(context).doesNotHaveBean(DispatcherServlet.class); + assertThat(context) + .doesNotHaveBean(DispatcherServletPathProvider.class); }); } @@ -73,7 +76,8 @@ public class DispatcherServletAutoConfigurationTests { @Test public void registrationOverrideWithDispatcherServletWrongName() { this.contextRunner - .withUserConfiguration(CustomDispatcherServletDifferentName.class) + .withUserConfiguration(CustomDispatcherServletDifferentName.class, + CustomDispatcherServletPathProvider.class) .run((context) -> { ServletRegistrationBean registration = context .getBean(ServletRegistrationBean.class); @@ -86,8 +90,8 @@ public class DispatcherServletAutoConfigurationTests { @Test public void registrationOverrideWithAutowiredServlet() { - this.contextRunner.withUserConfiguration(CustomAutowiredRegistration.class) - .run((context) -> { + this.contextRunner.withUserConfiguration(CustomAutowiredRegistration.class, + CustomDispatcherServletPathProvider.class).run((context) -> { ServletRegistrationBean registration = context .getBean(ServletRegistrationBean.class); assertThat(registration.getUrlMappings()).containsExactly("/foo"); @@ -112,6 +116,40 @@ public class DispatcherServletAutoConfigurationTests { }); } + @Test + public void pathProviderNotCreatedWhenMultipleDispatcherServletsPresent() { + this.contextRunner + .withUserConfiguration(CustomDispatcherServletDifferentName.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(DispatcherServletPathProvider.class)); + } + + @Test + public void pathProviderWhenCustomDispatcherServletSameNameShouldReturnConfiguredServletPath() { + this.contextRunner.withUserConfiguration(CustomDispatcherServletSameName.class) + .withPropertyValues("spring.mvc.servlet.path:/spring") + .run((context) -> assertThat(context + .getBean(DispatcherServletPathProvider.class).getServletPath()) + .isEqualTo("/spring")); + } + + @Test + public void pathProviderNotCreatedWhenDefaultDispatcherServletNotAvailable() { + this.contextRunner + .withUserConfiguration(CustomDispatcherServletDifferentName.class, + NonServletConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(DispatcherServletPathProvider.class)); + } + + @Test + public void pathProviderNotCreatedWhenCustomRegistrationBeanPresent() { + this.contextRunner + .withUserConfiguration(CustomDispatcherServletRegistration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(DispatcherServletPathProvider.class)); + } + @Test public void multipartConfig() { this.contextRunner.withUserConfiguration(MultipartConfiguration.class) @@ -198,6 +236,16 @@ public class DispatcherServletAutoConfigurationTests { } + @Configuration + protected static class CustomDispatcherServletPathProvider { + + @Bean + public DispatcherServletPathProvider dispatcherServletPathProvider() { + return mock(DispatcherServletPathProvider.class); + } + + } + @Configuration protected static class CustomAutowiredRegistration { @@ -210,6 +258,11 @@ public class DispatcherServletAutoConfigurationTests { return registration; } + @Bean + public DispatcherServletPathProvider dispatcherServletPathProvider() { + return mock(DispatcherServletPathProvider.class); + } + } @Configuration @@ -232,6 +285,30 @@ public class DispatcherServletAutoConfigurationTests { } + @Configuration + protected static class CustomDispatcherServletSameName { + + @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) + public DispatcherServlet dispatcherServlet() { + return new DispatcherServlet(); + } + + } + + @Configuration + protected static class CustomDispatcherServletRegistration { + + @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) + public ServletRegistrationBean dispatcherServletRegistration( + DispatcherServlet dispatcherServlet) { + ServletRegistrationBean registration = new ServletRegistrationBean<>( + dispatcherServlet, "/foo"); + registration.setName("customDispatcher"); + return registration; + } + + } + private static class MockMultipartResolver implements MultipartResolver { @Override