WebMvcConfigurationSupport.java 41.1 KB
Newer Older
1
/*
2
 * Copyright 2002-2019 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.config.annotation;

import java.util.ArrayList;
20
import java.util.Collections;
21
import java.util.HashMap;
22
import java.util.List;
23
import java.util.Locale;
24
import java.util.Map;
25
import java.util.function.Predicate;
26 27 28
import javax.servlet.ServletContext;

import org.springframework.beans.BeanUtils;
29
import org.springframework.beans.factory.BeanFactoryUtils;
30 31 32 33 34
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
35
import org.springframework.context.annotation.Lazy;
R
Rossen Stoyanchev 已提交
36 37 38
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
39 40
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
41
import org.springframework.http.MediaType;
42 43 44
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
45
import org.springframework.http.converter.ResourceRegionHttpMessageConverter;
46
import org.springframework.http.converter.StringHttpMessageConverter;
47
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
48 49
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
50
import org.springframework.http.converter.json.GsonHttpMessageConverter;
51
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
52
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
53
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
54
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
55
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
56
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
57
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
58
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
59
import org.springframework.lang.Nullable;
60
import org.springframework.util.AntPathMatcher;
61
import org.springframework.util.Assert;
62
import org.springframework.util.ClassUtils;
63
import org.springframework.util.PathMatcher;
64
import org.springframework.validation.Errors;
65
import org.springframework.validation.MessageCodesResolver;
66 67
import org.springframework.validation.Validator;
import org.springframework.web.HttpRequestHandler;
68
import org.springframework.web.accept.ContentNegotiationManager;
69
import org.springframework.web.bind.WebDataBinder;
70 71
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.ServletContextAware;
72
import org.springframework.web.cors.CorsConfiguration;
73
import org.springframework.web.method.support.CompositeUriComponentsContributor;
R
Rossen Stoyanchev 已提交
74 75
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
J
Juergen Hoeller 已提交
76 77 78 79
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ViewResolver;
80 81
import org.springframework.web.servlet.function.support.HandlerFunctionAdapter;
import org.springframework.web.servlet.function.support.RouterFunctionMapping;
82
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
83 84 85
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
86
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
87 88 89 90 91
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
92
import org.springframework.web.servlet.mvc.method.annotation.JsonViewRequestBodyAdvice;
93
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
94 95 96
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
97 98
import org.springframework.web.servlet.resource.ResourceUrlProvider;
import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor;
99
import org.springframework.web.servlet.view.InternalResourceViewResolver;
100
import org.springframework.web.servlet.view.ViewResolverComposite;
101
import org.springframework.web.util.UrlPathHelper;
102 103

/**
104
 * This is the main class providing the configuration behind the MVC Java config.
105 106
 * It is typically imported by adding {@link EnableWebMvc @EnableWebMvc} to an
 * application {@link Configuration @Configuration} class. An alternative more
107
 * advanced option is to extend directly from this class and override methods as
J
Juergen Hoeller 已提交
108
 * necessary, remembering to add {@link Configuration @Configuration} to the
109
 * subclass and {@link Bean @Bean} to overridden {@link Bean @Bean} methods.
J
Juergen Hoeller 已提交
110
 * For more details see the javadoc of {@link EnableWebMvc @EnableWebMvc}.
111
 *
P
Phillip Webb 已提交
112
 * <p>This class registers the following {@link HandlerMapping HandlerMappings}:</p>
113
 * <ul>
J
Juergen Hoeller 已提交
114 115 116 117 118 119 120 121 122 123
 * <li>{@link RequestMappingHandlerMapping}
 * ordered at 0 for mapping requests to annotated controller methods.
 * <li>{@link HandlerMapping}
 * ordered at 1 to map URL paths directly to view names.
 * <li>{@link BeanNameUrlHandlerMapping}
 * ordered at 2 to map URL paths to controller bean names.
 * <li>{@link HandlerMapping}
 * ordered at {@code Integer.MAX_VALUE-1} to serve static resource requests.
 * <li>{@link HandlerMapping}
 * ordered at {@code Integer.MAX_VALUE} to forward requests to the default servlet.
124 125
 * </ul>
 *
P
Phillip Webb 已提交
126
 * <p>Registers these {@link HandlerAdapter HandlerAdapters}:
127
 * <ul>
J
Juergen Hoeller 已提交
128 129 130
 * <li>{@link RequestMappingHandlerAdapter}
 * for processing requests with annotated controller methods.
 * <li>{@link HttpRequestHandlerAdapter}
P
Phillip Webb 已提交
131
 * for processing requests with {@link HttpRequestHandler HttpRequestHandlers}.
J
Juergen Hoeller 已提交
132
 * <li>{@link SimpleControllerHandlerAdapter}
P
Phillip Webb 已提交
133
 * for processing requests with interface-based {@link Controller Controllers}.
134 135
 * </ul>
 *
136 137
 * <p>Registers a {@link HandlerExceptionResolverComposite} with this chain of
 * exception resolvers:
138
 * <ul>
139 140 141 142
 * <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
 * {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
 * <li>{@link ResponseStatusExceptionResolver} for exceptions annotated with
 * {@link org.springframework.web.bind.annotation.ResponseStatus}.
J
Juergen Hoeller 已提交
143 144
 * <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring
 * exception types
145 146
 * </ul>
 *
147
 * <p>Registers an {@link AntPathMatcher} and a {@link UrlPathHelper}
148 149
 * to be used by:
 * <ul>
J
Juergen Hoeller 已提交
150 151 152
 * <li>the {@link RequestMappingHandlerMapping},
 * <li>the {@link HandlerMapping} for ViewControllers
 * <li>and the {@link HandlerMapping} for serving resources
153 154 155
 * </ul>
 * Note that those beans can be configured with a {@link PathMatchConfigurer}.
 *
156 157
 * <p>Both the {@link RequestMappingHandlerAdapter} and the
 * {@link ExceptionHandlerExceptionResolver} are configured with default
158
 * instances of the following by default:
159
 * <ul>
J
Juergen Hoeller 已提交
160 161
 * <li>a {@link ContentNegotiationManager}
 * <li>a {@link DefaultFormattingConversionService}
162
 * <li>an {@link org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean}
J
Juergen Hoeller 已提交
163
 * if a JSR-303 implementation is available on the classpath
P
Phillip Webb 已提交
164
 * <li>a range of {@link HttpMessageConverter HttpMessageConverters} depending on the third-party
J
Juergen Hoeller 已提交
165
 * libraries available on the classpath.
166
 * </ul>
167
 *
168
 * @author Rossen Stoyanchev
169
 * @author Brian Clozel
170
 * @author Sebastien Deleuze
171
 * @since 3.1
J
Juergen Hoeller 已提交
172 173
 * @see EnableWebMvc
 * @see WebMvcConfigurer
174
 */
175
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
176

J
Juergen Hoeller 已提交
177
	private static final boolean romePresent;
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

	private static final boolean jaxb2Present;

	private static final boolean jackson2Present;

	private static final boolean jackson2XmlPresent;

	private static final boolean jackson2SmilePresent;

	private static final boolean jackson2CborPresent;

	private static final boolean gsonPresent;

	private static final boolean jsonbPresent;

	static {
		ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
		romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
		jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
		jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
						ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
		jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
		jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
		jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
		gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
		jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
	}
205

206

207
	@Nullable
208 209
	private ApplicationContext applicationContext;

210
	@Nullable
J
Juergen Hoeller 已提交
211 212
	private ServletContext servletContext;

213
	@Nullable
214 215
	private List<Object> interceptors;

216
	@Nullable
J
Juergen Hoeller 已提交
217 218
	private PathMatchConfigurer pathMatchConfigurer;

219
	@Nullable
220 221
	private ContentNegotiationManager contentNegotiationManager;

222
	@Nullable
223 224
	private List<HandlerMethodArgumentResolver> argumentResolvers;

225
	@Nullable
226 227
	private List<HandlerMethodReturnValueHandler> returnValueHandlers;

228
	@Nullable
229
	private List<HttpMessageConverter<?>> messageConverters;
230

231
	@Nullable
232
	private Map<String, CorsConfiguration> corsConfigurations;
233

234 235

	/**
J
Juergen Hoeller 已提交
236
	 * Set the Spring {@link ApplicationContext}, e.g. for resource loading.
237
	 */
238
	@Override
239
	public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
J
Juergen Hoeller 已提交
240
		this.applicationContext = applicationContext;
241 242
	}

243 244 245 246
	/**
	 * Return the associated Spring {@link ApplicationContext}.
	 * @since 4.2
	 */
247 248
	@Nullable
	public final ApplicationContext getApplicationContext() {
249 250 251
		return this.applicationContext;
	}

252
	/**
J
Juergen Hoeller 已提交
253 254
	 * Set the {@link javax.servlet.ServletContext}, e.g. for resource handling,
	 * looking up file extensions, etc.
255
	 */
256
	@Override
257
	public void setServletContext(@Nullable ServletContext servletContext) {
J
Juergen Hoeller 已提交
258
		this.servletContext = servletContext;
259
	}
260

261 262 263 264
	/**
	 * Return the associated {@link javax.servlet.ServletContext}.
	 * @since 4.2
	 */
265 266
	@Nullable
	public final ServletContext getServletContext() {
267 268
		return this.servletContext;
	}
269

270

271
	/**
272
	 * Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
273
	 * requests to annotated controllers.
274 275 276
	 */
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {
277 278 279 280 281
		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		mapping.setInterceptors(getInterceptors());
		mapping.setContentNegotiationManager(mvcContentNegotiationManager());
		mapping.setCorsConfigurations(getCorsConfigurations());
282 283

		PathMatchConfigurer configurer = getPathMatchConfigurer();
284

285 286 287
		Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
		if (useSuffixPatternMatch != null) {
			mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
288
		}
289
		Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
290 291
		if (useRegisteredSuffixPatternMatch != null) {
			mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
292
		}
293
		Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
294 295
		if (useTrailingSlashMatch != null) {
			mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
296
		}
297

298 299
		UrlPathHelper pathHelper = configurer.getUrlPathHelper();
		if (pathHelper != null) {
300
			mapping.setUrlPathHelper(pathHelper);
301
		}
302 303
		PathMatcher pathMatcher = configurer.getPathMatcher();
		if (pathMatcher != null) {
304
			mapping.setPathMatcher(pathMatcher);
305
		}
306
		Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
307 308 309 310
		if (pathPrefixes != null) {
			mapping.setPathPrefixes(pathPrefixes);
		}

311
		return mapping;
312 313
	}

314
	/**
315
	 * Protected method for plugging in a custom subclass of
316
	 * {@link RequestMappingHandlerMapping}.
317
	 * @since 4.0
318 319 320 321 322
	 */
	protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
		return new RequestMappingHandlerMapping();
	}

323
	/**
324
	 * Provide access to the shared handler interceptors used to configure
J
Juergen Hoeller 已提交
325 326
	 * {@link HandlerMapping} instances with.
	 * <p>This method cannot be overridden; use {@link #addInterceptors} instead.
327 328
	 */
	protected final Object[] getInterceptors() {
329
		if (this.interceptors == null) {
330 331 332
			InterceptorRegistry registry = new InterceptorRegistry();
			addInterceptors(registry);
			registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
333
			registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
334
			this.interceptors = registry.getInterceptors();
335
		}
336
		return this.interceptors.toArray();
337
	}
338

339
	/**
340
	 * Override this method to add Spring MVC interceptors for
341
	 * pre- and post-processing of controller invocation.
342
	 * @see InterceptorRegistry
343
	 */
344
	protected void addInterceptors(InterceptorRegistry registry) {
345 346
	}

J
Juergen Hoeller 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
	/**
	 * Callback for building the {@link PathMatchConfigurer}.
	 * Delegates to {@link #configurePathMatch}.
	 * @since 4.1
	 */
	protected PathMatchConfigurer getPathMatchConfigurer() {
		if (this.pathMatchConfigurer == null) {
			this.pathMatchConfigurer = new PathMatchConfigurer();
			configurePathMatch(this.pathMatchConfigurer);
		}
		return this.pathMatchConfigurer;
	}

	/**
	 * Override this method to configure path matching options.
	 * @since 4.0.3
P
Phillip Webb 已提交
363
	 * @see PathMatchConfigurer
J
Juergen Hoeller 已提交
364
	 */
365
	protected void configurePathMatch(PathMatchConfigurer configurer) {
J
Juergen Hoeller 已提交
366 367
	}

368 369
	/**
	 * Return a global {@link PathMatcher} instance for path matching
P
Phillip Webb 已提交
370
	 * patterns in {@link HandlerMapping HandlerMappings}.
371 372 373 374 375 376 377
	 * This instance can be configured using the {@link PathMatchConfigurer}
	 * in {@link #configurePathMatch(PathMatchConfigurer)}.
	 * @since 4.1
	 */
	@Bean
	public PathMatcher mvcPathMatcher() {
		PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
378
		return (pathMatcher != null ? pathMatcher : new AntPathMatcher());
379 380 381 382
	}

	/**
	 * Return a global {@link UrlPathHelper} instance for path matching
P
Phillip Webb 已提交
383
	 * patterns in {@link HandlerMapping HandlerMappings}.
384 385 386 387 388 389 390 391 392 393
	 * This instance can be configured using the {@link PathMatchConfigurer}
	 * in {@link #configurePathMatch(PathMatchConfigurer)}.
	 * @since 4.1
	 */
	@Bean
	public UrlPathHelper mvcUrlPathHelper() {
		UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
		return (pathHelper != null ? pathHelper : new UrlPathHelper());
	}

394 395 396 397 398 399 400
	/**
	 * Return a {@link ContentNegotiationManager} instance to use to determine
	 * requested {@linkplain MediaType media types} in a given request.
	 */
	@Bean
	public ContentNegotiationManager mvcContentNegotiationManager() {
		if (this.contentNegotiationManager == null) {
401 402
			ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
			configurer.mediaTypes(getDefaultMediaTypes());
403
			configureContentNegotiation(configurer);
404
			this.contentNegotiationManager = configurer.buildContentNegotiationManager();
405 406 407 408 409
		}
		return this.contentNegotiationManager;
	}

	protected Map<String, MediaType> getDefaultMediaTypes() {
410
		Map<String, MediaType> map = new HashMap<>(4);
411 412
		if (romePresent) {
			map.put("atom", MediaType.APPLICATION_ATOM_XML);
413
			map.put("rss", MediaType.APPLICATION_RSS_XML);
414
		}
415
		if (jaxb2Present || jackson2XmlPresent) {
416 417
			map.put("xml", MediaType.APPLICATION_XML);
		}
418
		if (jackson2Present || gsonPresent || jsonbPresent) {
419 420
			map.put("json", MediaType.APPLICATION_JSON);
		}
421 422 423 424 425 426
		if (jackson2SmilePresent) {
			map.put("smile", MediaType.valueOf("application/x-jackson-smile"));
		}
		if (jackson2CborPresent) {
			map.put("cbor", MediaType.valueOf("application/cbor"));
		}
427 428 429 430 431 432 433 434 435 436
		return map;
	}

	/**
	 * Override this method to configure content negotiation.
	 * @see DefaultServletHandlerConfigurer
	 */
	protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
	}

437
	/**
438 439 440
	 * Return a handler mapping ordered at 1 to map URL paths directly to
	 * view names. To configure view controllers, override
	 * {@link #addViewControllers}.
441 442
	 */
	@Bean
443
	@Nullable
444
	public HandlerMapping viewControllerHandlerMapping() {
445
		ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
446
		addViewControllers(registry);
447

448
		AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
449 450 451
		if (handlerMapping == null) {
			return null;
		}
452 453
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
454
		handlerMapping.setInterceptors(getInterceptors());
455
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
456 457 458 459
		return handlerMapping;
	}

	/**
460 461
	 * Override this method to add view controllers.
	 * @see ViewControllerRegistry
462
	 */
463
	protected void addViewControllers(ViewControllerRegistry registry) {
464
	}
465

466
	/**
467
	 * Return a {@link BeanNameUrlHandlerMapping} ordered at 2 to map URL
468
	 * paths to controller bean names.
469 470 471 472 473 474
	 */
	@Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2);
		mapping.setInterceptors(getInterceptors());
475
		mapping.setCorsConfigurations(getCorsConfigurations());
476 477 478
		return mapping;
	}

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
	/**
	 * Return a {@link RouterFunctionMapping} ordered at 3 to map
	 * {@linkplain org.springframework.web.servlet.function.RouterFunction router functions}.
	 * Consider overriding one of these other more fine-grained methods:
	 * <ul>
	 * <li>{@link #addInterceptors} for adding handler interceptors.
	 * <li>{@link #addCorsMappings} to configure cross origin requests processing.
	 * <li>{@link #configureMessageConverters} for adding custom message converters.
	 * </ul>
	 * @since 5.2
	 */
	@Bean
	public RouterFunctionMapping routerFunctionMapping() {
		RouterFunctionMapping mapping = new RouterFunctionMapping();
		mapping.setOrder(3);
		mapping.setInterceptors(getInterceptors());
		mapping.setCorsConfigurations(getCorsConfigurations());
		mapping.setMessageConverters(getMessageConverters());
		return mapping;
	}

500
	/**
501 502
	 * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
	 * resource handlers. To configure resource handling, override
503
	 * {@link #addResourceHandlers}.
504 505
	 */
	@Bean
506
	@Nullable
507
	public HandlerMapping resourceHandlerMapping() {
508 509 510
		Assert.state(this.applicationContext != null, "No ApplicationContext set");
		Assert.state(this.servletContext != null, "No ServletContext set");

511
		ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
512
				this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
513
		addResourceHandlers(registry);
514

515
		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
516 517
		if (handlerMapping == null) {
			return null;
518
		}
519 520 521 522
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
		handlerMapping.setInterceptors(getInterceptors());
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
523
		return handlerMapping;
524 525 526
	}

	/**
527
	 * Override this method to add resource handlers for serving static resources.
528
	 * @see ResourceHandlerRegistry
529
	 */
530
	protected void addResourceHandlers(ResourceHandlerRegistry registry) {
531 532
	}

533 534 535 536
	/**
	 * A {@link ResourceUrlProvider} bean for use with the MVC dispatcher.
	 * @since 4.1
	 */
537
	@Bean
538 539
	public ResourceUrlProvider mvcResourceUrlProvider() {
		ResourceUrlProvider urlProvider = new ResourceUrlProvider();
540 541
		UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
		if (pathHelper != null) {
542
			urlProvider.setUrlPathHelper(pathHelper);
543 544 545
		}
		PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
		if (pathMatcher != null) {
546
			urlProvider.setPathMatcher(pathMatcher);
547
		}
548
		return urlProvider;
549 550
	}

551
	/**
552 553 554
	 * Return a handler mapping ordered at Integer.MAX_VALUE with a mapped
	 * default servlet handler. To configure "default" Servlet handling,
	 * override {@link #configureDefaultServletHandling}.
555 556
	 */
	@Bean
557
	@Nullable
558
	public HandlerMapping defaultServletHandlerMapping() {
559 560
		Assert.state(this.servletContext != null, "No ServletContext set");
		DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
561
		configureDefaultServletHandling(configurer);
562
		return configurer.buildHandlerMapping();
563 564 565
	}

	/**
566
	 * Override this method to configure "default" Servlet handling.
567 568 569 570 571 572
	 * @see DefaultServletHandlerConfigurer
	 */
	protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
	}

	/**
573 574
	 * Returns a {@link RequestMappingHandlerAdapter} for processing requests
	 * through annotated controller methods. Consider overriding one of these
575
	 * other more fine-grained methods:
R
Rossen Stoyanchev 已提交
576
	 * <ul>
J
Juergen Hoeller 已提交
577 578 579
	 * <li>{@link #addArgumentResolvers} for adding custom argument resolvers.
	 * <li>{@link #addReturnValueHandlers} for adding custom return value handlers.
	 * <li>{@link #configureMessageConverters} for adding custom message converters.
R
Rossen Stoyanchev 已提交
580
	 * </ul>
581 582 583
	 */
	@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
584
		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
585
		adapter.setContentNegotiationManager(mvcContentNegotiationManager());
586
		adapter.setMessageConverters(getMessageConverters());
587
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
588 589
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
590

591
		if (jackson2Present) {
592 593
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
594 595
		}

596 597 598 599 600 601 602 603
		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
604 605
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
606

607 608 609
		return adapter;
	}

610
	/**
611
	 * Protected method for plugging in a custom subclass of
612
	 * {@link RequestMappingHandlerAdapter}.
613
	 * @since 4.3
614 615 616 617 618
	 */
	protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
		return new RequestMappingHandlerAdapter();
	}

619 620 621 622 623 624 625 626 627 628
	/**
	 * Returns a {@link HandlerFunctionAdapter} for processing requests through
	 * {@linkplain org.springframework.web.servlet.function.HandlerFunction handler functions}.
	 * @since 5.2
	 */
	@Bean
	public HandlerFunctionAdapter handlerFunctionAdapter() {
		return new HandlerFunctionAdapter();
	}

629
	/**
630 631 632 633 634 635 636
	 * Return the {@link ConfigurableWebBindingInitializer} to use for
	 * initializing all {@link WebDataBinder} instances.
	 */
	protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
		ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
		initializer.setConversionService(mvcConversionService());
		initializer.setValidator(mvcValidator());
637 638 639 640
		MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
		if (messageCodesResolver != null) {
			initializer.setMessageCodesResolver(messageCodesResolver);
		}
641 642 643
		return initializer;
	}

644 645 646
	/**
	 * Override this method to provide a custom {@link MessageCodesResolver}.
	 */
647
	@Nullable
648 649 650 651 652 653 654 655 656 657 658
	protected MessageCodesResolver getMessageCodesResolver() {
		return null;
	}

	/**
	 * Override this method to configure asynchronous request processing options.
	 * @see AsyncSupportConfigurer
	 */
	protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
	}

659
	/**
J
Juergen Hoeller 已提交
660 661
	 * Return a {@link FormattingConversionService} for use with annotated controllers.
	 * <p>See {@link #addFormatters} as an alternative to overriding this method.
662 663 664 665 666 667 668 669
	 */
	@Bean
	public FormattingConversionService mvcConversionService() {
		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		addFormatters(conversionService);
		return conversionService;
	}

670
	/**
J
Juergen Hoeller 已提交
671 672 673
	 * Override this method to add custom {@link Converter} and/or {@link Formatter}
	 * delegates to the common {@link FormattingConversionService}.
	 * @see #mvcConversionService()
674 675 676 677
	 */
	protected void addFormatters(FormatterRegistry registry) {
	}

678
	/**
679
	 * Return a global {@link Validator} instance for example for validating
680 681 682
	 * {@code @ModelAttribute} and {@code @RequestBody} method arguments.
	 * Delegates to {@link #getValidator()} first and if that returns {@code null}
	 * checks the classpath for the presence of a JSR-303 implementations
683
	 * before creating a {@code OptionalValidatorFactoryBean}.If a JSR-303
684 685 686 687 688 689 690 691 692
	 * implementation is not available, a no-op {@link Validator} is returned.
	 */
	@Bean
	public Validator mvcValidator() {
		Validator validator = getValidator();
		if (validator == null) {
			if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
				Class<?> clazz;
				try {
693
					String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
694
					clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
695
				}
J
Juergen Hoeller 已提交
696
				catch (ClassNotFoundException | LinkageError ex) {
697
					throw new BeanInitializationException("Failed to resolve default validator class", ex);
698
				}
699
				validator = (Validator) BeanUtils.instantiateClass(clazz);
700 701
			}
			else {
702
				validator = new NoOpValidator();
703 704 705 706 707
			}
		}
		return validator;
	}

708 709 710
	/**
	 * Override this method to provide a custom {@link Validator}.
	 */
711
	@Nullable
712 713 714 715
	protected Validator getValidator() {
		return null;
	}

716 717
	/**
	 * Provide access to the shared custom argument resolvers used by the
J
Juergen Hoeller 已提交
718 719
	 * {@link RequestMappingHandlerAdapter} and the {@link ExceptionHandlerExceptionResolver}.
	 * <p>This method cannot be overridden; use {@link #addArgumentResolvers} instead.
720
	 * @since 4.3
721 722 723
	 */
	protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
		if (this.argumentResolvers == null) {
724
			this.argumentResolvers = new ArrayList<>();
725 726 727 728 729
			addArgumentResolvers(this.argumentResolvers);
		}
		return this.argumentResolvers;
	}

730
	/**
J
Juergen Hoeller 已提交
731 732 733 734 735
	 * Add custom {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}
	 * to use in addition to the ones registered by default.
	 * <p>Custom argument resolvers are invoked before built-in resolvers except for
	 * those that rely on the presence of annotations (e.g. {@code @RequestParameter},
	 * {@code @PathVariable}, etc). The latter can be customized by configuring the
736
	 * {@link RequestMappingHandlerAdapter} directly.
J
Juergen Hoeller 已提交
737
	 * @param argumentResolvers the list of custom converters (initially an empty list)
R
Rossen Stoyanchev 已提交
738 739 740 741
	 */
	protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
	}

742 743
	/**
	 * Provide access to the shared return value handlers used by the
J
Juergen Hoeller 已提交
744 745
	 * {@link RequestMappingHandlerAdapter} and the {@link ExceptionHandlerExceptionResolver}.
	 * <p>This method cannot be overridden; use {@link #addReturnValueHandlers} instead.
746
	 * @since 4.3
747 748 749
	 */
	protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
		if (this.returnValueHandlers == null) {
750
			this.returnValueHandlers = new ArrayList<>();
751 752 753 754 755
			addReturnValueHandlers(this.returnValueHandlers);
		}
		return this.returnValueHandlers;
	}

R
Rossen Stoyanchev 已提交
756
	/**
J
Juergen Hoeller 已提交
757 758 759 760 761
	 * Add custom {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}
	 * in addition to the ones registered by default.
	 * <p>Custom return value handlers are invoked before built-in ones except for
	 * those that rely on the presence of annotations (e.g. {@code @ResponseBody},
	 * {@code @ModelAttribute}, etc). The latter can be customized by configuring the
762
	 * {@link RequestMappingHandlerAdapter} directly.
J
Juergen Hoeller 已提交
763
	 * @param returnValueHandlers the list of custom handlers (initially an empty list)
R
Rossen Stoyanchev 已提交
764 765 766 767
	 */
	protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
	}

768
	/**
J
Juergen Hoeller 已提交
769 770
	 * Provides access to the shared {@link HttpMessageConverter HttpMessageConverters}
	 * used by the {@link RequestMappingHandlerAdapter} and the
771
	 * {@link ExceptionHandlerExceptionResolver}.
J
Juergen Hoeller 已提交
772 773
	 * <p>This method cannot be overridden; use {@link #configureMessageConverters} instead.
	 * Also see {@link #addDefaultHttpMessageConverters} for adding default message converters.
774 775
	 */
	protected final List<HttpMessageConverter<?>> getMessageConverters() {
776
		if (this.messageConverters == null) {
777
			this.messageConverters = new ArrayList<>();
778 779 780
			configureMessageConverters(this.messageConverters);
			if (this.messageConverters.isEmpty()) {
				addDefaultHttpMessageConverters(this.messageConverters);
781
			}
782
			extendMessageConverters(this.messageConverters);
783
		}
784
		return this.messageConverters;
785 786 787
	}

	/**
J
Juergen Hoeller 已提交
788 789 790 791 792 793 794
	 * Override this method to add custom {@link HttpMessageConverter HttpMessageConverters}
	 * to use with the {@link RequestMappingHandlerAdapter} and the
	 * {@link ExceptionHandlerExceptionResolver}.
	 * <p>Adding converters to the list turns off the default converters that would
	 * otherwise be registered by default. Also see {@link #addDefaultHttpMessageConverters}
	 * for adding default message converters.
	 * @param converters a list to add message converters to (initially an empty list)
795 796 797 798
	 */
	protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

799
	/**
J
Juergen Hoeller 已提交
800 801 802 803
	 * Override this method to extend or modify the list of converters after it has
	 * been configured. This may be useful for example to allow default converters
	 * to be registered and then insert a custom converter through this method.
	 * @param converters the list of configured converters to extend
804 805
	 * @since 4.1.3
	 */
806 807 808
	protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
	}

809
	/**
810
	 * Adds a set of default HttpMessageConverter instances to the given list.
J
Juergen Hoeller 已提交
811
	 * Subclasses can call this method from {@link #configureMessageConverters}.
812
	 * @param messageConverters the list to add the default message converters to
813 814
	 */
	protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
J
Juergen Hoeller 已提交
815 816
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316
817 818

		messageConverters.add(new ByteArrayHttpMessageConverter());
J
Juergen Hoeller 已提交
819
		messageConverters.add(stringHttpMessageConverter);
820
		messageConverters.add(new ResourceHttpMessageConverter());
821
		messageConverters.add(new ResourceRegionHttpMessageConverter());
822 823 824
		try {
			messageConverters.add(new SourceHttpMessageConverter<>());
		}
J
Juergen Hoeller 已提交
825 826
		catch (Throwable ex) {
			// Ignore when no TransformerFactory implementation is available...
827
		}
828
		messageConverters.add(new AllEncompassingFormHttpMessageConverter());
829

830 831 832 833
		if (romePresent) {
			messageConverters.add(new AtomFeedHttpMessageConverter());
			messageConverters.add(new RssChannelHttpMessageConverter());
		}
J
Juergen Hoeller 已提交
834 835

		if (jackson2XmlPresent) {
836 837 838 839 840
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
841 842
		}
		else if (jaxb2Present) {
843 844
			messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
		}
J
Juergen Hoeller 已提交
845

846
		if (jackson2Present) {
847 848 849 850 851
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
852
		}
853 854 855
		else if (gsonPresent) {
			messageConverters.add(new GsonHttpMessageConverter());
		}
856 857 858
		else if (jsonbPresent) {
			messageConverters.add(new JsonbHttpMessageConverter());
		}
859 860

		if (jackson2SmilePresent) {
861 862 863 864 865
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
866 867
		}
		if (jackson2CborPresent) {
868 869 870 871 872
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
873
		}
874
	}
875

876
	/**
877 878
	 * Return an instance of {@link CompositeUriComponentsContributor} for use with
	 * {@link org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder}.
879
	 * @since 4.0
880 881
	 */
	@Bean
882 883 884
	public CompositeUriComponentsContributor mvcUriComponentsContributor() {
		return new CompositeUriComponentsContributor(
				requestMappingHandlerAdapter().getArgumentResolvers(), mvcConversionService());
885 886
	}

887
	/**
888
	 * Returns a {@link HttpRequestHandlerAdapter} for processing requests
P
Phillip Webb 已提交
889
	 * with {@link HttpRequestHandler HttpRequestHandlers}.
890 891 892 893 894 895 896
	 */
	@Bean
	public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
		return new HttpRequestHandlerAdapter();
	}

	/**
897
	 * Returns a {@link SimpleControllerHandlerAdapter} for processing requests
898
	 * with interface-based controllers.
899 900 901 902 903 904 905
	 */
	@Bean
	public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
		return new SimpleControllerHandlerAdapter();
	}

	/**
J
Juergen Hoeller 已提交
906 907 908 909 910 911
	 * Returns a {@link HandlerExceptionResolverComposite} containing a list of exception
	 * resolvers obtained either through {@link #configureHandlerExceptionResolvers} or
	 * through {@link #addDefaultHandlerExceptionResolvers}.
	 * <p><strong>Note:</strong> This method cannot be made final due to CGLIB constraints.
	 * Rather than overriding it, consider overriding {@link #configureHandlerExceptionResolvers}
	 * which allows for providing a list of resolvers.
R
Rossen Stoyanchev 已提交
912 913
	 */
	@Bean
914
	public HandlerExceptionResolver handlerExceptionResolver() {
915
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
R
Rossen Stoyanchev 已提交
916 917 918 919
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
			addDefaultHandlerExceptionResolvers(exceptionResolvers);
		}
920
		extendHandlerExceptionResolvers(exceptionResolvers);
R
Rossen Stoyanchev 已提交
921 922 923 924 925 926 927
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}

	/**
928
	 * Override this method to configure the list of
J
Juergen Hoeller 已提交
929 930 931
	 * {@link HandlerExceptionResolver HandlerExceptionResolvers} to use.
	 * <p>Adding resolvers to the list turns off the default resolvers that would otherwise
	 * be registered by default. Also see {@link #addDefaultHandlerExceptionResolvers}
932
	 * that can be used to add the default exception resolvers.
J
Juergen Hoeller 已提交
933
	 * @param exceptionResolvers a list to add exception resolvers to (initially an empty list)
R
Rossen Stoyanchev 已提交
934 935 936 937
	 */
	protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
	}

938 939
	/**
	 * Override this method to extend or modify the list of
J
Juergen Hoeller 已提交
940 941 942
	 * {@link HandlerExceptionResolver HandlerExceptionResolvers} after it has been configured.
	 * <p>This may be useful for example to allow default resolvers to be registered
	 * and then insert a custom one through this method.
943
	 * @param exceptionResolvers the list of configured resolvers to extend.
J
Juergen Hoeller 已提交
944
	 * @since 4.3
945 946 947 948
	 */
	protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
	}

R
Rossen Stoyanchev 已提交
949
	/**
J
Juergen Hoeller 已提交
950 951
	 * A method available to subclasses for adding default
	 * {@link HandlerExceptionResolver HandlerExceptionResolvers}.
R
Rossen Stoyanchev 已提交
952
	 * <p>Adds the following exception resolvers:
953
	 * <ul>
954 955 956 957 958
	 * <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
	 * {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
	 * <li>{@link ResponseStatusExceptionResolver} for exceptions annotated with
	 * {@link org.springframework.web.bind.annotation.ResponseStatus}.
	 * <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring exception types
959 960
	 * </ul>
	 */
R
Rossen Stoyanchev 已提交
961
	protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
962 963 964
		ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
		exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager());
		exceptionHandlerResolver.setMessageConverters(getMessageConverters());
965 966
		exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
		exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
967
		if (jackson2Present) {
968 969
			exceptionHandlerResolver.setResponseBodyAdvice(
					Collections.singletonList(new JsonViewResponseBodyAdvice()));
970
		}
971 972 973
		if (this.applicationContext != null) {
			exceptionHandlerResolver.setApplicationContext(this.applicationContext);
		}
974 975
		exceptionHandlerResolver.afterPropertiesSet();
		exceptionResolvers.add(exceptionHandlerResolver);
J
Juergen Hoeller 已提交
976

977 978 979
		ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
		responseStatusResolver.setMessageSource(this.applicationContext);
		exceptionResolvers.add(responseStatusResolver);
980

J
Juergen Hoeller 已提交
981
		exceptionResolvers.add(new DefaultHandlerExceptionResolver());
982
	}
983

984
	/**
985
	 * Protected method for plugging in a custom subclass of
986
	 * {@link ExceptionHandlerExceptionResolver}.
987
	 * @since 4.3
988 989 990 991 992
	 */
	protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
		return new ExceptionHandlerExceptionResolver();
	}

993
	/**
994 995
	 * Register a {@link ViewResolverComposite} that contains a chain of view resolvers
	 * to use for view resolution.
R
Polish  
Rossen Stoyanchev 已提交
996 997 998 999
	 * By default this resolver is ordered at 0 unless content negotiation view
	 * resolution is used in which case the order is raised to
	 * {@link org.springframework.core.Ordered#HIGHEST_PRECEDENCE
	 * Ordered.HIGHEST_PRECEDENCE}.
1000 1001 1002
	 * <p>If no other resolvers are configured,
	 * {@link ViewResolverComposite#resolveViewName(String, Locale)} returns null in order
	 * to allow other potential {@link ViewResolver} beans to resolve views.
R
Polish  
Rossen Stoyanchev 已提交
1003
	 * @since 4.1
1004 1005
	 */
	@Bean
1006
	public ViewResolver mvcViewResolver() {
1007 1008
		ViewResolverRegistry registry = new ViewResolverRegistry(
				mvcContentNegotiationManager(), this.applicationContext);
1009 1010
		configureViewResolvers(registry);

1011
		if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
1012
			String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
1013
					this.applicationContext, ViewResolver.class, true, false);
1014
			if (names.length == 1) {
1015 1016 1017 1018
				registry.getViewResolvers().add(new InternalResourceViewResolver());
			}
		}

1019 1020
		ViewResolverComposite composite = new ViewResolverComposite();
		composite.setOrder(registry.getOrder());
1021
		composite.setViewResolvers(registry.getViewResolvers());
1022 1023 1024
		if (this.applicationContext != null) {
			composite.setApplicationContext(this.applicationContext);
		}
1025 1026 1027
		if (this.servletContext != null) {
			composite.setServletContext(this.servletContext);
		}
1028
		return composite;
1029 1030
	}

1031 1032 1033 1034 1035
	/**
	 * Override this method to configure view resolution.
	 * @see ViewResolverRegistry
	 */
	protected void configureViewResolvers(ViewResolverRegistry registry) {
1036 1037
	}

1038
	/**
J
Juergen Hoeller 已提交
1039 1040
	 * Return the registered {@link CorsConfiguration} objects,
	 * keyed by path pattern.
1041 1042 1043 1044
	 * @since 4.2
	 */
	protected final Map<String, CorsConfiguration> getCorsConfigurations() {
		if (this.corsConfigurations == null) {
1045 1046
			CorsRegistry registry = new CorsRegistry();
			addCorsMappings(registry);
1047 1048 1049 1050
			this.corsConfigurations = registry.getCorsConfigurations();
		}
		return this.corsConfigurations;
	}
1051

1052
	/**
1053
	 * Override this method to configure cross origin requests processing.
1054
	 * @since 4.2
1055
	 * @see CorsRegistry
1056
	 */
1057
	protected void addCorsMappings(CorsRegistry registry) {
1058 1059
	}

P
Phillip Webb 已提交
1060 1061
	@Bean
	@Lazy
1062 1063 1064 1065 1066
	public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
		return new HandlerMappingIntrospector();
	}


1067 1068 1069 1070 1071 1072 1073 1074
	private static final class NoOpValidator implements Validator {

		@Override
		public boolean supports(Class<?> clazz) {
			return false;
		}

		@Override
1075
		public void validate(@Nullable Object target, Errors errors) {
1076 1077 1078
		}
	}

1079
}