HandlerMappingIntrospector is a bean

This commit is contained in:
Rossen Stoyanchev
2017-09-27 21:28:49 -04:00
parent 126ac849e5
commit 0f1bd49f6d
5 changed files with 124 additions and 49 deletions

View File

@@ -29,6 +29,7 @@ import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
import org.springframework.web.util.UrlPathHelper;
@@ -57,11 +58,14 @@ abstract class MvcNamespaceUtils {
private static final String CORS_CONFIGURATION_BEAN_NAME = "mvcCorsConfigurations";
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
registerBeanNameUrlHandlerMapping(parserContext, source);
registerHttpRequestHandlerAdapter(parserContext, source);
registerSimpleControllerHandlerAdapter(parserContext, source);
registerHandlerMappingIntrospector(parserContext, source);
}
/**
@@ -186,6 +190,21 @@ abstract class MvcNamespaceUtils {
return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
}
/**
* Registers an {@link HandlerMappingIntrospector} under a well-known name
* unless already registered.
*/
private static void registerHandlerMappingIntrospector(ParserContext parserContext, @Nullable Object source) {
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)){
RootBeanDefinition beanDef = new RootBeanDefinition(HandlerMappingIntrospector.class);
beanDef.setSource(source);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDef.setLazyInit(true);
parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, beanDef);
parserContext.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME));
}
}
/**
* Find the {@code ContentNegotiationManager} bean created by or registered
* with the {@code annotation-driven} element.

View File

@@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
@@ -82,6 +83,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
@@ -1022,6 +1024,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
protected void addCorsMappings(CorsRegistry registry) {
}
@Bean @Lazy
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
return new HandlerMappingIntrospector();
}
private static final class EmptyHandlerMapping extends AbstractHandlerMapping {

View File

@@ -18,20 +18,23 @@ package org.springframework.web.servlet.handler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsConfiguration;
@@ -56,33 +59,66 @@ import org.springframework.web.servlet.HandlerMapping;
* @author Rossen Stoyanchev
* @since 4.3.1
*/
public class HandlerMappingIntrospector implements CorsConfigurationSource {
public class HandlerMappingIntrospector
implements CorsConfigurationSource, ApplicationContextAware, InitializingBean {
private final List<HandlerMapping> handlerMappings;
@Nullable
private ApplicationContext applicationContext;
@Nullable
private List<HandlerMapping> handlerMappings;
/**
* Constructor for use with {@link ApplicationContextAware}.
*/
public HandlerMappingIntrospector() {
}
/**
* Constructor that detects the configured {@code HandlerMapping}s in the
* given {@code ApplicationContext} or falls back on
* "DispatcherServlet.properties" like the {@code DispatcherServlet}.
*/
@Deprecated
public HandlerMappingIntrospector(ApplicationContext context) {
this.handlerMappings = initHandlerMappings(context);
}
private static List<HandlerMapping> initHandlerMappings(ApplicationContext context) {
/**
* Return the configured HandlerMapping's.
*/
public List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
if (this.handlerMappings == null) {
Assert.notNull(this.applicationContext, "No ApplicationContext");
this.handlerMappings = initHandlerMappings(this.applicationContext);
}
}
private static List<HandlerMapping> initHandlerMappings(ApplicationContext applicationContext) {
Map<String, HandlerMapping> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
applicationContext, HandlerMapping.class, true, false);
if (!beans.isEmpty()) {
List<HandlerMapping> mappings = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(mappings);
return mappings;
return Collections.unmodifiableList(mappings);
}
return initDefaultHandlerMappings(context);
return Collections.unmodifiableList(initFallback(applicationContext));
}
private static List<HandlerMapping> initDefaultHandlerMappings(ApplicationContext context) {
private static List<HandlerMapping> initFallback(ApplicationContext applicationContext) {
Properties props;
String path = "DispatcherServlet.properties";
try {
@@ -99,7 +135,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource {
for (String name : names) {
try {
Class<?> clazz = ClassUtils.forName(name, DispatcherServlet.class.getClassLoader());
Object mapping = context.getAutowireCapableBeanFactory().createBean(clazz);
Object mapping = applicationContext.getAutowireCapableBeanFactory().createBean(clazz);
result.add((HandlerMapping) mapping);
}
catch (ClassNotFoundException ex) {
@@ -110,13 +146,6 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource {
}
/**
* Return the configured HandlerMapping's.
*/
public List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings;
}
/**
* Find the {@link HandlerMapping} that would handle the given request and
* return it as a {@link MatchableHandlerMapping} that can be used to test
@@ -129,6 +158,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource {
*/
@Nullable
public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest request) throws Exception {
Assert.notNull(this.handlerMappings, "Handler mappings not initialized");
HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request);
for (HandlerMapping handlerMapping : this.handlerMappings) {
Object handler = handlerMapping.getHandler(wrapper);
@@ -146,6 +176,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource {
@Override
@Nullable
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
Assert.notNull(this.handlerMappings, "Handler mappings not initialized");
HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request);
for (HandlerMapping handlerMapping : this.handlerMappings) {
HandlerExecutionChain handler = null;