Commit 0af9d202 authored by Dave Syer's avatar Dave Syer

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]
parent 86064f48
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.web; package org.springframework.boot.autoconfigure.web;
import java.util.Arrays;
import javax.servlet.Servlet; import javax.servlet.Servlet;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
...@@ -39,11 +41,15 @@ import org.springframework.boot.context.embedded.ServletContextInitializer; ...@@ -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.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean; 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.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
...@@ -58,6 +64,11 @@ import org.springframework.web.servlet.DispatcherServlet; ...@@ -58,6 +64,11 @@ import org.springframework.web.servlet.DispatcherServlet;
@Import(EmbeddedServletContainerCustomizerBeanPostProcessorRegistrar.class) @Import(EmbeddedServletContainerCustomizerBeanPostProcessorRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration { 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 * Add the {@link DispatcherServlet} unless the user has defined their own
* {@link ServletContextInitializer}s. * {@link ServletContextInitializer}s.
...@@ -65,12 +76,12 @@ public class EmbeddedServletContainerAutoConfiguration { ...@@ -65,12 +76,12 @@ public class EmbeddedServletContainerAutoConfiguration {
@ConditionalOnClass(DispatcherServlet.class) @ConditionalOnClass(DispatcherServlet.class)
public static class DispatcherServletConfiguration { public static class DispatcherServletConfiguration {
@Bean @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
@ConditionalOnMissingBean(value = { ServletContextInitializer.class, @Conditional(DefaultServletCondition.class)
Servlet.class }, search = SearchStrategy.CURRENT)
public DispatcherServlet dispatcherServlet() { public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet(); return new DispatcherServlet();
} }
} }
/** /**
...@@ -134,4 +145,24 @@ public class EmbeddedServletContainerAutoConfiguration { ...@@ -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;
}
}
} }
...@@ -22,7 +22,6 @@ import org.junit.Test; ...@@ -22,7 +22,6 @@ import org.junit.Test;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 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.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
...@@ -31,6 +30,7 @@ import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFac ...@@ -31,6 +30,7 @@ import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFac
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
...@@ -53,6 +53,24 @@ public class EmbeddedServletContainerAutoConfigurationTests { ...@@ -53,6 +53,24 @@ public class EmbeddedServletContainerAutoConfigurationTests {
verifyContext(); 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 @Test
public void containerHasNoServletContext() throws Exception { public void containerHasNoServletContext() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext( this.context = new AnnotationConfigEmbeddedWebApplicationContext(
...@@ -74,7 +92,10 @@ public class EmbeddedServletContainerAutoConfigurationTests { ...@@ -74,7 +92,10 @@ public class EmbeddedServletContainerAutoConfigurationTests {
private void verifyContext() { private void verifyContext() {
MockEmbeddedServletContainerFactory containerFactory = getContainerFactory(); 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", verify(containerFactory.getServletContext()).addServlet("dispatcherServlet",
servlet); servlet);
} }
...@@ -94,6 +115,26 @@ public class EmbeddedServletContainerAutoConfigurationTests { ...@@ -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 @Component
public static class EnsureContainerHasNoServletContext implements BeanPostProcessor { public static class EnsureContainerHasNoServletContext implements BeanPostProcessor {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment