Commit 004363ce authored by Phillip Webb's avatar Phillip Webb

Use WebMvcConfigurer to add resource handlers

Move resource handler auto-configuration logic back to the
`WebMvcConfigurer` so that they also get applied to child contexts.

Closes gh-25743
parent ee76d603
...@@ -17,11 +17,10 @@ ...@@ -17,11 +17,10 @@
package org.springframework.boot.autoconfigure.web.servlet; package org.springframework.boot.autoconfigure.web.servlet;
import java.time.Duration; import java.time.Duration;
import java.util.HashSet; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.servlet.Servlet; import javax.servlet.Servlet;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
...@@ -54,6 +53,7 @@ import org.springframework.boot.autoconfigure.web.ResourceProperties; ...@@ -54,6 +53,7 @@ import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy; import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters; import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;
import org.springframework.boot.autoconfigure.web.format.WebConversionService; import org.springframework.boot.autoconfigure.web.format.WebConversionService;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.AutoConfigurationResourceHandlerRegistry.RegistrationType;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.Format; import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.Format;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.convert.ApplicationConversionService;
...@@ -76,6 +76,7 @@ import org.springframework.format.FormatterRegistry; ...@@ -76,6 +76,7 @@ import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionService; import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.DefaultMessageCodesResolver;
...@@ -110,6 +111,7 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry ...@@ -110,6 +111,7 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.FixedLocaleResolver; import org.springframework.web.servlet.i18n.FixedLocaleResolver;
...@@ -184,6 +186,10 @@ public class WebMvcAutoConfiguration { ...@@ -184,6 +186,10 @@ public class WebMvcAutoConfiguration {
@Order(0) @Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer { public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties; private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory; private final ListableBeanFactory beanFactory;
...@@ -194,13 +200,14 @@ public class WebMvcAutoConfiguration { ...@@ -194,13 +200,14 @@ public class WebMvcAutoConfiguration {
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations; private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer; private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
public WebMvcAutoConfigurationAdapter(WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ObjectProvider<HttpMessageConverters> messageConvertersProvider, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties; this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider; this.messageConvertersProvider = messageConvertersProvider;
...@@ -321,6 +328,39 @@ public class WebMvcAutoConfiguration { ...@@ -321,6 +328,39 @@ public class WebMvcAutoConfiguration {
ApplicationConversionService.addBeans(registry, this.beanFactory); ApplicationConversionService.addBeans(registry, this.beanFactory);
} }
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),
this.resourceProperties.getStaticLocations());
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
if (registry.hasMappingForPattern(pattern)) {
return;
}
ResourceHandlerRegistration registration = AutoConfigurationResourceHandlerRegistry
.addResourceHandler(registry, RegistrationType.AUTO_CONFIGURATION, pattern);
registration.addResourceLocations(locations);
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
customizeResourceHandlerRegistration(registration);
}
private Integer getSeconds(Duration cachePeriod) {
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
}
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
@Bean @Bean
@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class }) @ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })
@ConditionalOnMissingFilterBean(RequestContextFilter.class) @ConditionalOnMissingFilterBean(RequestContextFilter.class)
...@@ -336,31 +376,22 @@ public class WebMvcAutoConfiguration { ...@@ -336,31 +376,22 @@ public class WebMvcAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware { public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties; private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties; private final WebMvcProperties mvcProperties;
private final WebMvcRegistrations mvcRegistrations; private final WebMvcRegistrations mvcRegistrations;
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
private ResourceLoader resourceLoader; private ResourceLoader resourceLoader;
private final ListableBeanFactory beanFactory; private final ListableBeanFactory beanFactory;
private final Set<String> autoConfiguredResourceHandlers = new HashSet<>();
public EnableWebMvcConfiguration(ResourceProperties resourceProperties, public EnableWebMvcConfiguration(ResourceProperties resourceProperties,
ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ListableBeanFactory beanFactory) {
this.resourceProperties = resourceProperties; this.resourceProperties = resourceProperties;
this.mvcProperties = mvcPropertiesProvider.getIfAvailable(); this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique(); this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
...@@ -402,70 +433,28 @@ public class WebMvcAutoConfiguration { ...@@ -402,70 +433,28 @@ public class WebMvcAutoConfiguration {
@Bean @Bean
@Override @Override
public HandlerMapping resourceHandlerMapping(UrlPathHelper urlPathHelper, PathMatcher pathMatcher, public HandlerMapping resourceHandlerMapping(@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
ContentNegotiationManager contentNegotiationManager, FormattingConversionService conversionService, @Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
ResourceUrlProvider resourceUrlProvider) { @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
HandlerMapping mapping = super.resourceHandlerMapping(urlPathHelper, pathMatcher, contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService,
conversionService, resourceUrlProvider); @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
if (mapping instanceof SimpleUrlHandlerMapping) { Assert.state(getApplicationContext() != null, "No ApplicationContext set");
addServletContextResourceHandlerMapping((SimpleUrlHandlerMapping) mapping); Assert.state(getServletContext() != null, "No ServletContext set");
AutoConfigurationResourceHandlerRegistry registry = new AutoConfigurationResourceHandlerRegistry(
getApplicationContext(), getServletContext(), contentNegotiationManager, urlPathHelper,
this.mvcProperties);
addResourceHandlers(registry);
AbstractHandlerMapping mapping = registry.getHandlerMapping();
if (mapping == null) {
return null;
} }
mapping.setPathMatcher(pathMatcher);
mapping.setUrlPathHelper(urlPathHelper);
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping; return mapping;
} }
private void addServletContextResourceHandlerMapping(SimpleUrlHandlerMapping mapping) {
Map<String, ?> urlMap = mapping.getUrlMap();
String pattern = this.mvcProperties.getStaticPathPattern();
Object handler = urlMap.get(pattern);
if (handler instanceof ResourceHttpRequestHandler
&& this.autoConfiguredResourceHandlers.contains(pattern)) {
addServletContextResourceHandlerMapping((ResourceHttpRequestHandler) handler);
}
}
private void addServletContextResourceHandlerMapping(ResourceHttpRequestHandler handler) {
ServletContext servletContext = getServletContext();
if (servletContext != null) {
List<Resource> locations = handler.getLocations();
locations.add(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),
this.resourceProperties.getStaticLocations());
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
if (registry.hasMappingForPattern(pattern)) {
return;
}
ResourceHandlerRegistration registration = registry.addResourceHandler(pattern);
registration.addResourceLocations(locations);
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
customizeResourceHandlerRegistration(registration);
this.autoConfiguredResourceHandlers.add(pattern);
}
private Integer getSeconds(Duration cachePeriod) {
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
}
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
@Bean @Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
...@@ -677,4 +666,84 @@ public class WebMvcAutoConfiguration { ...@@ -677,4 +666,84 @@ public class WebMvcAutoConfiguration {
} }
/**
* {@link ResourceHandlerRegistry} that tracks auto-configuration and when appropriate
* adds the {@link ServletContextResource} for {@code /}.
*/
static class AutoConfigurationResourceHandlerRegistry
extends org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry {
private final ServletContext servletContext;
private final WebMvcProperties mvcProperties;
private final Map<String, RegistrationType> registrations = new LinkedHashMap<>();
AutoConfigurationResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext,
ContentNegotiationManager contentNegotiationManager, UrlPathHelper pathHelper,
WebMvcProperties mvcProperties) {
super(applicationContext, servletContext, contentNegotiationManager, pathHelper);
this.servletContext = servletContext;
this.mvcProperties = mvcProperties;
}
@Override
public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
return addResourceHandler(RegistrationType.STANDARD, pathPatterns);
}
ResourceHandlerRegistration addResourceHandler(RegistrationType type, String... pathPatterns) {
for (String pathPattern : pathPatterns) {
this.registrations.put(pathPattern, type);
}
return super.addResourceHandler(pathPatterns);
}
@Override
protected AbstractHandlerMapping getHandlerMapping() {
SimpleUrlHandlerMapping mapping = (SimpleUrlHandlerMapping) super.getHandlerMapping();
reconfigure(mapping);
return mapping;
}
private void reconfigure(SimpleUrlHandlerMapping mapping) {
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (this.registrations.get(staticPathPattern) == RegistrationType.AUTO_CONFIGURATION) {
addServletContextResourceHandlerMapping(mapping, staticPathPattern);
}
}
private void addServletContextResourceHandlerMapping(SimpleUrlHandlerMapping mapping,
String staticPathPattern) {
Object handler = mapping.getUrlMap().get(staticPathPattern);
if (handler instanceof ResourceHttpRequestHandler) {
addServletContextResourceHandlerMapping((ResourceHttpRequestHandler) handler);
}
}
private void addServletContextResourceHandlerMapping(ResourceHttpRequestHandler handler) {
if (this.servletContext != null) {
List<Resource> locations = handler.getLocations();
locations.add(new ServletContextResource(this.servletContext, SERVLET_LOCATION));
}
}
static ResourceHandlerRegistration addResourceHandler(ResourceHandlerRegistry registry, RegistrationType type,
String... pathPatterns) {
if (registry instanceof AutoConfigurationResourceHandlerRegistry) {
return ((AutoConfigurationResourceHandlerRegistry) registry).addResourceHandler(type, pathPatterns);
}
return registry.addResourceHandler(pathPatterns);
}
enum RegistrationType {
STANDARD,
AUTO_CONFIGURATION
}
}
} }
...@@ -33,6 +33,7 @@ import java.util.concurrent.Executor; ...@@ -33,6 +33,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.ValidatorFactory; import javax.validation.ValidatorFactory;
...@@ -50,9 +51,11 @@ import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguratio ...@@ -50,9 +51,11 @@ import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguratio
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
...@@ -81,6 +84,7 @@ import org.springframework.web.accept.ParameterContentNegotiationStrategy; ...@@ -81,6 +84,7 @@ import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.FormContentFilter; import org.springframework.web.filter.FormContentFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.filter.HiddenHttpMethodFilter;
...@@ -95,6 +99,7 @@ import org.springframework.web.servlet.ViewResolver; ...@@ -95,6 +99,7 @@ import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
...@@ -898,6 +903,25 @@ class WebMvcAutoConfigurationTests { ...@@ -898,6 +903,25 @@ class WebMvcAutoConfigurationTests {
}); });
} }
@Test // gh-25743
void addResourceHandlersAppliesToChildAndParentContext() {
try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {
context.register(WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
ResourceHandlersWithChildAndParentContextConfiguration.class);
context.refresh();
SimpleUrlHandlerMapping resourceHandlerMapping = context.getBean("resourceHandlerMapping",
SimpleUrlHandlerMapping.class);
DispatcherServlet extraDispatcherServlet = context.getBean("extraDispatcherServlet",
DispatcherServlet.class);
SimpleUrlHandlerMapping extraResourceHandlerMapping = extraDispatcherServlet.getWebApplicationContext()
.getBean("resourceHandlerMapping", SimpleUrlHandlerMapping.class);
assertThat(resourceHandlerMapping).isNotSameAs(extraResourceHandlerMapping);
assertThat(resourceHandlerMapping.getUrlMap()).containsKey("/**");
assertThat(extraResourceHandlerMapping.getUrlMap()).containsKey("/**");
}
}
private void assertCacheControl(AssertableWebApplicationContext context) { private void assertCacheControl(AssertableWebApplicationContext context) {
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class)); Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
assertThat(handlerMap).hasSize(2); assertThat(handlerMap).hasSize(2);
...@@ -1330,4 +1354,49 @@ class WebMvcAutoConfigurationTests { ...@@ -1330,4 +1354,49 @@ class WebMvcAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false)
static class ResourceHandlersWithChildAndParentContextConfiguration {
@Bean
TomcatServletWebServerFactory webServerFactory() {
return new TomcatServletWebServerFactory(0);
}
@Bean
ServletRegistrationBean<?> additionalDispatcherServlet(DispatcherServlet extraDispatcherServlet) {
ServletRegistrationBean<?> registration = new ServletRegistrationBean<>(extraDispatcherServlet, "/extra/*");
registration.setName("additionalDispatcherServlet");
registration.setLoadOnStartup(1);
return registration;
}
@Bean
private DispatcherServlet extraDispatcherServlet() throws ServletException {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(ResourceHandlersWithChildAndParentContextChildConfiguration.class);
dispatcherServlet.setApplicationContext(applicationContext);
return dispatcherServlet;
}
}
@Configuration(proxyBeanMethods = false)
@EnableWebMvc
static class ResourceHandlersWithChildAndParentContextChildConfiguration {
@Bean
WebMvcConfigurer myConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/testtesttest");
}
};
}
}
} }
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