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]
This commit is contained in:
Dave Syer 2013-08-12 10:32:49 +01:00
parent 86064f48e0
commit 0af9d2022a
2 changed files with 77 additions and 5 deletions

View File

@ -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;
}
}
}

View File

@ -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 {