Skip to content

Commit b6ca8a9

Browse files
committed
HandlerMappingIntrospector is a bean
1 parent 8071f13 commit b6ca8a9

File tree

5 files changed

+122
-48
lines changed

5 files changed

+122
-48
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/config/MvcNamespaceUtils.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.util.PathMatcher;
2929
import org.springframework.web.cors.CorsConfiguration;
3030
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
31+
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
3132
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
3233
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
3334
import org.springframework.web.util.UrlPathHelper;
@@ -56,11 +57,14 @@ abstract class MvcNamespaceUtils {
5657

5758
private static final String CORS_CONFIGURATION_BEAN_NAME = "mvcCorsConfigurations";
5859

60+
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
61+
5962

6063
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
6164
registerBeanNameUrlHandlerMapping(parserContext, source);
6265
registerHttpRequestHandlerAdapter(parserContext, source);
6366
registerSimpleControllerHandlerAdapter(parserContext, source);
67+
registerHandlerMappingIntrospector(parserContext, source);
6468
}
6569

6670
/**
@@ -184,6 +188,21 @@ else if (corsConfigurations != null) {
184188
return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
185189
}
186190

191+
/**
192+
* Registers an {@link HandlerMappingIntrospector} under a well-known name
193+
* unless already registered.
194+
*/
195+
private static void registerHandlerMappingIntrospector(ParserContext parserContext, Object source) {
196+
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)){
197+
RootBeanDefinition beanDef = new RootBeanDefinition(HandlerMappingIntrospector.class);
198+
beanDef.setSource(source);
199+
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
200+
beanDef.setLazyInit(true);
201+
parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, beanDef);
202+
parserContext.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME));
203+
}
204+
}
205+
187206
/**
188207
* Find the {@code ContentNegotiationManager} bean created by or registered
189208
* with the {@code annotation-driven} element.

spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.context.ApplicationContextAware;
3434
import org.springframework.context.annotation.Bean;
3535
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.context.annotation.Lazy;
3637
import org.springframework.core.convert.converter.Converter;
3738
import org.springframework.format.Formatter;
3839
import org.springframework.format.FormatterRegistry;
@@ -77,6 +78,7 @@
7778
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
7879
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
7980
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
81+
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
8082
import org.springframework.web.servlet.mvc.Controller;
8183
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
8284
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
@@ -954,6 +956,12 @@ protected final Map<String, CorsConfiguration> getCorsConfigurations() {
954956
protected void addCorsMappings(CorsRegistry registry) {
955957
}
956958

959+
@Bean @Lazy
960+
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
961+
return new HandlerMappingIntrospector();
962+
}
963+
964+
957965

958966
private static final class EmptyHandlerMapping extends AbstractHandlerMapping {
959967

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,22 @@
1818

1919
import java.io.IOException;
2020
import java.util.ArrayList;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Properties;
2425
import javax.servlet.http.HttpServletRequest;
2526
import javax.servlet.http.HttpServletRequestWrapper;
2627

2728
import org.springframework.beans.factory.BeanFactoryUtils;
29+
import org.springframework.beans.factory.InitializingBean;
2830
import org.springframework.context.ApplicationContext;
31+
import org.springframework.context.ApplicationContextAware;
2932
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
3033
import org.springframework.core.io.ClassPathResource;
3134
import org.springframework.core.io.Resource;
3235
import org.springframework.core.io.support.PropertiesLoaderUtils;
36+
import org.springframework.util.Assert;
3337
import org.springframework.util.ClassUtils;
3438
import org.springframework.util.StringUtils;
3539
import org.springframework.web.cors.CorsConfiguration;
@@ -54,33 +58,64 @@
5458
* @author Rossen Stoyanchev
5559
* @since 4.3.1
5660
*/
57-
public class HandlerMappingIntrospector implements CorsConfigurationSource {
61+
public class HandlerMappingIntrospector
62+
implements CorsConfigurationSource, ApplicationContextAware, InitializingBean {
5863

59-
private final List<HandlerMapping> handlerMappings;
64+
private ApplicationContext applicationContext;
65+
66+
private List<HandlerMapping> handlerMappings;
6067

6168

69+
/**
70+
* Constructor for use with {@link ApplicationContextAware}.
71+
*/
72+
public HandlerMappingIntrospector() {
73+
}
74+
6275
/**
6376
* Constructor that detects the configured {@code HandlerMapping}s in the
6477
* given {@code ApplicationContext} or falls back on
6578
* "DispatcherServlet.properties" like the {@code DispatcherServlet}.
6679
*/
80+
@Deprecated
6781
public HandlerMappingIntrospector(ApplicationContext context) {
6882
this.handlerMappings = initHandlerMappings(context);
6983
}
7084

7185

72-
private static List<HandlerMapping> initHandlerMappings(ApplicationContext context) {
86+
/**
87+
* Return the configured HandlerMapping's.
88+
*/
89+
public List<HandlerMapping> getHandlerMappings() {
90+
return this.handlerMappings;
91+
}
92+
93+
94+
@Override
95+
public void setApplicationContext(ApplicationContext applicationContext) {
96+
this.applicationContext = applicationContext;
97+
}
98+
99+
@Override
100+
public void afterPropertiesSet() {
101+
if (this.handlerMappings == null) {
102+
Assert.notNull(this.applicationContext, "No ApplicationContext");
103+
this.handlerMappings = initHandlerMappings(this.applicationContext);
104+
}
105+
}
106+
107+
private static List<HandlerMapping> initHandlerMappings(ApplicationContext applicationContext) {
73108
Map<String, HandlerMapping> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
74-
context, HandlerMapping.class, true, false);
109+
applicationContext, HandlerMapping.class, true, false);
75110
if (!beans.isEmpty()) {
76111
List<HandlerMapping> mappings = new ArrayList<HandlerMapping>(beans.values());
77112
AnnotationAwareOrderComparator.sort(mappings);
78-
return mappings;
113+
return Collections.unmodifiableList(mappings);
79114
}
80-
return initDefaultHandlerMappings(context);
115+
return Collections.unmodifiableList(initFallback(applicationContext));
81116
}
82117

83-
private static List<HandlerMapping> initDefaultHandlerMappings(ApplicationContext context) {
118+
private static List<HandlerMapping> initFallback(ApplicationContext applicationContext) {
84119
Properties props;
85120
String path = "DispatcherServlet.properties";
86121
try {
@@ -97,7 +132,7 @@ private static List<HandlerMapping> initDefaultHandlerMappings(ApplicationContex
97132
for (String name : names) {
98133
try {
99134
Class<?> clazz = ClassUtils.forName(name, DispatcherServlet.class.getClassLoader());
100-
Object mapping = context.getAutowireCapableBeanFactory().createBean(clazz);
135+
Object mapping = applicationContext.getAutowireCapableBeanFactory().createBean(clazz);
101136
result.add((HandlerMapping) mapping);
102137
}
103138
catch (ClassNotFoundException ex) {
@@ -108,13 +143,6 @@ private static List<HandlerMapping> initDefaultHandlerMappings(ApplicationContex
108143
}
109144

110145

111-
/**
112-
* Return the configured HandlerMapping's.
113-
*/
114-
public List<HandlerMapping> getHandlerMappings() {
115-
return this.handlerMappings;
116-
}
117-
118146
/**
119147
* Find the {@link HandlerMapping} that would handle the given request and
120148
* return it as a {@link MatchableHandlerMapping} that can be used to test
@@ -126,6 +154,7 @@ public List<HandlerMapping> getHandlerMappings() {
126154
* @throws Exception if any of the HandlerMapping's raise an exception
127155
*/
128156
public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest request) throws Exception {
157+
Assert.notNull(this.handlerMappings, "Handler mappings not initialized");
129158
HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request);
130159
for (HandlerMapping handlerMapping : this.handlerMappings) {
131160
Object handler = handlerMapping.getHandler(wrapper);
@@ -142,6 +171,7 @@ public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest req
142171

143172
@Override
144173
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
174+
Assert.notNull(this.handlerMappings, "Handler mappings not initialized");
145175
HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request);
146176
for (HandlerMapping handlerMapping : this.handlerMappings) {
147177
HandlerExecutionChain handler = null;

0 commit comments

Comments
 (0)