diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index ba442c32af8..82de68a7143 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -17,9 +17,7 @@ package org.springframework.boot.autoconfigure.web.servlet; import java.time.Duration; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -66,7 +64,6 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.task.AsyncTaskExecutor; @@ -106,7 +103,6 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.i18n.FixedLocaleResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; @@ -114,7 +110,6 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.resource.AppCacheManifestTransformer; import org.springframework.web.servlet.resource.EncodedResourceResolver; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.servlet.resource.ResourceResolver; import org.springframework.web.servlet.resource.ResourceUrlProvider; import org.springframework.web.servlet.resource.VersionResourceResolver; @@ -370,48 +365,13 @@ public class WebMvcAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) - public static class FaviconConfiguration implements ResourceLoaderAware { - - private final ResourceProperties resourceProperties; - - private ResourceLoader resourceLoader; - - public FaviconConfiguration(ResourceProperties resourceProperties) { - this.resourceProperties = resourceProperties; - } + public static class FaviconConfiguration implements WebMvcConfigurer { @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - @Bean - public SimpleUrlHandlerMapping faviconHandlerMapping(FaviconRequestHandler handler) { - SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); - mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); - mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", handler)); - return mapping; - } - - @Bean - public FaviconRequestHandler faviconRequestHandler() { - return new FaviconRequestHandler(resolveFaviconLocations()); - } - - private List resolveFaviconLocations() { - String[] staticLocations = getResourceLocations(this.resourceProperties.getStaticLocations()); - List locations = new ArrayList<>(staticLocations.length + 1); - Arrays.stream(staticLocations).map(this.resourceLoader::getResource).forEach(locations::add); - locations.add(new ClassPathResource("/")); - return Collections.unmodifiableList(locations); - } - - } - - static final class FaviconRequestHandler extends ResourceHttpRequestHandler { - - FaviconRequestHandler(List locations) { - setLocations(locations); + public void addResourceHandlers(ResourceHandlerRegistry registry) { + if (!registry.hasMappingForPattern("favicon.ico")) { + registry.addResourceHandler("favicon.ico").addResourceLocations("classpath:favicon.ico"); + } } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index c1fe7bea2e3..f8bbf290086 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -24,6 +24,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -147,7 +148,7 @@ class WebMvcAutoConfigurationTests { @Test void handlerMappingsCreated() { - this.contextRunner.run((context) -> assertThat(context).getBeans(HandlerMapping.class).hasSize(6)); + this.contextRunner.run((context) -> assertThat(context).getBeans(HandlerMapping.class).hasSize(5)); } @Test @@ -195,7 +196,7 @@ class WebMvcAutoConfigurationTests { @Test void resourceHandlerMappingDisabled() { this.contextRunner.withPropertyValues("spring.resources.add-mappings:false") - .run((context) -> assertThat(context.getBean("resourceHandlerMapping")).isEqualTo(null)); + .run((context) -> assertThat(getResourceMappingLocations(context)).hasSize(1)); } @Test @@ -379,25 +380,14 @@ class WebMvcAutoConfigurationTests { @Test void faviconMapping() { - this.contextRunner.run((context) -> { - assertThat(context).getBeanNames(ResourceHttpRequestHandler.class).contains("faviconRequestHandler"); - assertThat(context).getBeans(SimpleUrlHandlerMapping.class).containsKey("faviconHandlerMapping"); - assertThat(getFaviconMappingLocations(context).get("/**/favicon.ico")).hasSize(6); - }); - } - - @Test - void faviconMappingUsesStaticLocations() { - this.contextRunner.withPropertyValues("spring.resources.static-locations=classpath:/static") - .run((context) -> assertThat(getFaviconMappingLocations(context).get("/**/favicon.ico")).hasSize(3)); + this.contextRunner + .run((context) -> assertThat(getResourceMappingLocations(context).get("/favicon.ico")).hasSize(1)); } @Test void faviconMappingDisabled() { - this.contextRunner.withPropertyValues("spring.mvc.favicon.enabled:false").run((context) -> { - assertThat(context).getBeans(ResourceHttpRequestHandler.class).doesNotContainKey("faviconRequestHandler"); - assertThat(context).getBeans(SimpleUrlHandlerMapping.class).doesNotContainKey("faviconHandlerMapping"); - }); + this.contextRunner.withPropertyValues("spring.mvc.favicon.enabled:false") + .run((context) -> assertThat(getResourceMappingLocations(context).get("/favicon.ico")).isNull()); } @Test @@ -667,11 +657,14 @@ class WebMvcAutoConfigurationTests { private void assertCachePeriod(AssertableWebApplicationContext context) { Map handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class)); - assertThat(handlerMap).hasSize(2); - for (Object handler : handlerMap.values()) { - if (handler instanceof ResourceHttpRequestHandler) { - assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(5); - assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()).isNull(); + assertThat(handlerMap).hasSize(3); + for (Entry entry : handlerMap.entrySet()) { + if (!entry.getKey().equals("/favicon.ico")) { + Object handler = entry.getValue(); + if (handler instanceof ResourceHttpRequestHandler) { + assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(5); + assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()).isNull(); + } } } } @@ -788,7 +781,7 @@ class WebMvcAutoConfigurationTests { private void assertCacheControl(AssertableWebApplicationContext context) { Map handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class)); - assertThat(handlerMap).hasSize(2); + assertThat(handlerMap).hasSize(3); for (Object handler : handlerMap.keySet()) { if (handler instanceof ResourceHttpRequestHandler) { assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(-1); @@ -798,10 +791,6 @@ class WebMvcAutoConfigurationTests { } } - protected Map> getFaviconMappingLocations(ApplicationContext context) { - return getMappingLocations(context.getBean("faviconHandlerMapping", HandlerMapping.class)); - } - protected Map> getResourceMappingLocations(ApplicationContext context) { return getMappingLocations(context.getBean("resourceHandlerMapping", HandlerMapping.class)); }