From 0af9d2022a8e9781a312e37377fe574feb29fc7d Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 12 Aug 2013 10:32:49 +0100 Subject: [PATCH] Allow user to supply servlets and filters and still get default DispatcherServlet Instead of not installing one at all if there is any ServletContextInitializer, Spring Boot will now install a DispatcherServlet if context does not contain one already with the magic name "dispatcherServlet". [Fixes #54674870] [bs-277] --- ...ddedServletContainerAutoConfiguration.java | 37 +++++++++++++-- ...ervletContainerAutoConfigurationTests.java | 45 ++++++++++++++++++- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java index bea36932e69..4bfb467f950 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.web; +import java.util.Arrays; + import javax.servlet.Servlet; import org.apache.catalina.startup.Tomcat; @@ -39,11 +41,15 @@ import org.springframework.boot.context.embedded.ServletContextInitializer; import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotationMetadata; import org.springframework.web.servlet.DispatcherServlet; @@ -58,6 +64,11 @@ import org.springframework.web.servlet.DispatcherServlet; @Import(EmbeddedServletContainerCustomizerBeanPostProcessorRegistrar.class) public class EmbeddedServletContainerAutoConfiguration { + /* + * The bean name for a DispatcherServlet that will be mapped to the root URL "/" + */ + public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; + /** * Add the {@link DispatcherServlet} unless the user has defined their own * {@link ServletContextInitializer}s. @@ -65,12 +76,12 @@ public class EmbeddedServletContainerAutoConfiguration { @ConditionalOnClass(DispatcherServlet.class) public static class DispatcherServletConfiguration { - @Bean - @ConditionalOnMissingBean(value = { ServletContextInitializer.class, - Servlet.class }, search = SearchStrategy.CURRENT) + @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) + @Conditional(DefaultServletCondition.class) public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); } + } /** @@ -134,4 +145,24 @@ public class EmbeddedServletContainerAutoConfiguration { } } } + + private static class DefaultServletCondition implements Condition { + + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] beans = beanFactory.getBeanNamesForType(DispatcherServlet.class, + false, false); + if (beans.length == 0) { + // No dispatcher servlet so no need to ask further questions + return true; + } + if (Arrays.asList(beans).contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) { + // An existing bean with the default name + return false; + } + return true; + } + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java index 2bb82f4e001..f3b7d7cfc9e 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java @@ -22,7 +22,6 @@ import org.junit.Test; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; @@ -31,6 +30,7 @@ import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFac import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; +import org.springframework.web.servlet.DispatcherServlet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -53,6 +53,24 @@ public class EmbeddedServletContainerAutoConfigurationTests { verifyContext(); } + @Test + public void contextAlreadyHasDispatcherServletWithDefaultName() throws Exception { + this.context = new AnnotationConfigEmbeddedWebApplicationContext( + DispatcherServletConfiguration.class, + EmbeddedContainerConfiguration.class, + EmbeddedServletContainerAutoConfiguration.class); + verifyContext(); + } + + @Test + public void contextAlreadyHasDispatcherServlet() throws Exception { + this.context = new AnnotationConfigEmbeddedWebApplicationContext( + SpringServletConfiguration.class, EmbeddedContainerConfiguration.class, + EmbeddedServletContainerAutoConfiguration.class); + verifyContext(); + assertEquals(2, this.context.getBeanNamesForType(DispatcherServlet.class).length); + } + @Test public void containerHasNoServletContext() throws Exception { this.context = new AnnotationConfigEmbeddedWebApplicationContext( @@ -74,7 +92,10 @@ public class EmbeddedServletContainerAutoConfigurationTests { private void verifyContext() { MockEmbeddedServletContainerFactory containerFactory = getContainerFactory(); - Servlet servlet = this.context.getBean(Servlet.class); + Servlet servlet = this.context + .getBean( + EmbeddedServletContainerAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME, + Servlet.class); verify(containerFactory.getServletContext()).addServlet("dispatcherServlet", servlet); } @@ -94,6 +115,26 @@ public class EmbeddedServletContainerAutoConfigurationTests { } + @Configuration + public static class DispatcherServletConfiguration { + + @Bean + public DispatcherServlet dispatcherServlet() { + return new DispatcherServlet(); + } + + } + + @Configuration + public static class SpringServletConfiguration { + + @Bean + public DispatcherServlet springServlet() { + return new DispatcherServlet(); + } + + } + @Component public static class EnsureContainerHasNoServletContext implements BeanPostProcessor {