docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(二):WebMvc装配过程.md
ƽʱУspringboot е web ĿĽ springboot Զ springMvc Ŀ̡
springMvc ԶװΪ
@Configuration(proxyBeanMethods = false)
// װ
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// ûԶWebMvc࣬ʹñ
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
// װ˳
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({
// DispatcherServlet Զװ
DispatcherServletAutoConfiguration.class,
// ̳߳صԶװ
TaskExecutionAutoConfiguration.class,
// jsr 303 ֤ܵԶװ
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
}
@AutoConfigureAfter עУWebMvcAutoConfiguration Ҫ DispatcherServletAutoConfiguration``TaskExecutionAutoConfiguration``ValidationAutoConfiguration װ֮װ䣬Що£
DispatcherServletAutoConfiguration``DispatcherServlet ԶװTaskExecutionAutoConfigurationִʵǴһ̳߳ValidationAutoConfigurationjsr 303 ֤Զװ䣬֤ @NotNull``@NotEmpty ע֤3 У springMvc йصֻ DispatcherServletAutoConfigurationʶһ
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
// Ҫ ServletWebServerFactoryAutoConfiguration Զװɺ
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
...
}
DispatcherServletAutoConfiguration Ҫ ServletWebServerFactoryAutoConfiguration ԶװɲŽװ䣬ʲôأ£Ǵ servlet tomcat, jetty, undertow ȣɵģ ServletWebServerFactoryAutoConfiguration
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
// һЩ
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
// 3 web
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
...
}
Կû @AutoConfigureAfter עˣ springMvc Զװ࣬ǵķʹʼ
ܽϼװ˳
ServletWebServerFactoryAutoConfigurationDispatcherServletAutoConfigurationWebMvcAutoConfigurationǵķҲ˳һЩԶװࡣ
ServletWebServerFactoryAutoConfiguration ԶװServletWebServerFactoryAutoConfiguration £
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
// һЩ
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
// 3 web
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
...
}
BeanPostProcessorsRegistrar``EmbeddedTomcat``EmbeddedJetty``EmbeddedUndertowһɣ
BeanPostProcessorsRegistrarBeanPostProcessorsRegistrar ServletWebServerFactoryAutoConfiguration ڲ࣬£
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
...
/**
* ImportBeanDefinitionRegistrar ķ
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
// ע
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
/**
* ע
*/
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
Ҫ spring עࣺWebServerFactoryCustomizerBeanPostProcessor``ErrorPageRegistrarBeanPostProcessorǷֱǸɶ
WebServerFactoryCustomizerBeanPostProcessorWebServerFactoryCustomizerBeanPostProcessor Ĵ£
public class WebServerFactoryCustomizerBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware {
...
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// bean WebServerFactory Ŵ
if (bean instanceof WebServerFactory) {
postProcessBeforeInitialization((WebServerFactory) bean);
}
return bean;
}
@SuppressWarnings("unchecked")
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
//
.invoke((customizer) -> customizer.customize(webServerFactory));
}
/**
* ȡ WebServerFactoryCustomizerõһɱ List
*/
private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
if (this.customizers == null) {
this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
/**
* ȡ beanFactory е WebServerFactoryCustomizer
*/
private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
return (Collection) this.beanFactory.getBeansOfType(
WebServerFactoryCustomizer.class, false, false).values();
}
}
WebServerFactory Զõģʵ BeanPostProcessor Ҫע postProcessBeforeInitialization(...)
WebServerFactoryCustomizerBeanPostProcessor postProcessBeforeInitialization(...) Уǰ bean WebServerFactoryȻȡ beanFactory Ϊ WebServerFactoryCustomizer beanȻЩ WebServerFactoryCustomizer õ WebServerFactorybean С
ҪԶ Tomcat ã
@Component
public class MyCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setPort(8091);
factory.setContextPath("/");
//
...
}
}
ServletWebServerFactoryAutoConfiguration ṩ WebServerFactoryCustomizer:
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
...
}
ӷö ServerProperties
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
...
}
ConfigurationProperties ע⣬prefix Ϊ "server"ö server ͷֵ֧£
磬ҪĶ˿ڣֻ application.properties üɣ
server.port=8080
ãͲˡ
ErrorPageRegistrarBeanPostProcessorErrorPageRegistrarBeanPostProcessor Ĵ£
public class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
/**
* BeanPostProcessorķbeanʼǰִ
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ErrorPageRegistry) {
// bean ErrorPageRegistry
postProcessBeforeInitialization((ErrorPageRegistry) bean);
}
return bean;
}
private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
for (ErrorPageRegistrar registrar : getRegistrars()) {
// עҳ
registrar.registerErrorPages(registry);
}
}
private Collection<ErrorPageRegistrar> getRegistrars() {
if (this.registrars == null) {
// ȡеĴҳ
this.registrars = new ArrayList<>(this.beanFactory.getBeansOfType(
ErrorPageRegistrar.class, false, false).values());
this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);
this.registrars = Collections.unmodifiableList(this.registrars);
}
return this.registrars;
}
...
}
Ҫע postProcessBeforeInitialization ̣
ErrorPageRegistryе 2ErrorPageRegistrar ͵ beanе 3registrar.registerErrorPages(registry) дҳҪ˵
ErrorPageRegistrarҳע ErrorPageRegistry ɻࣩErrorPageRegistryעࣨʵʸɻࣩҪԶҳʵ ErrorPageRegistry ӿڣ
@Component
public class MyErrorPage implements ErrorPageRegistrar {
/**
* עҳ
*/
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
// յõ ErrorPageRegistry#addErrorPages ע
errorPageRegistry.addErrorPages(new ErrorPage("/error/page"));
}
}
EmbeddedTomcatServletWebServerFactoryConfiguration.EmbeddedTomcat ࣺ
@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
// ע⣬ʱ
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
// ע ServletWebServerFactoryǿʵ tomcat װ
@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
// һЩ
factory.getTomcatConnectorCustomizers()
.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatContextCustomizers()
.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatProtocolHandlerCustomizers()
.addAll(protocolHandlerCustomizers.orderedStream()
.collect(Collectors.toList()));
return factory;
}
}
...
}
ҪǷ TomcatServletWebServerFactory beanעһЩ connectorCustomizers``contextCustomizers``protocolHandlerCustomizers ȲԶãЩǴ BeanPostProcessorsRegistrar ġ
иطҪһ£ʹ springboot ṩ TomcatServletWebServerFactoryǿԼʵ TomcatServletWebServerFactory
@Bean
public ServletWebServerFactory servletWebServerFactory() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
// Զĸ
...
return tomcat;
}
֮springboot ṩ tomcatServletWebServerFactory Ͳᴦˡ
EmbeddedJetty``EmbeddedUndertow EmbeddedTomcat ĴƣͲ˵ˡ
DispatcherServletAutoConfigurationDispatcherServletAutoConfigurationؼ£
public class DispatcherServletAutoConfiguration {
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME
= "dispatcherServletRegistration";
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {
/**
* DispatcherServlet.
* @param httpProperties http.
* @param webMvcProperties webMvc .
* @return ض
*/
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(HttpProperties httpProperties,
WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(
webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(
webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
/**
* ļϴ.
* @param resolver .
* @return ֵ.
*/
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
return resolver;
}
}
/**
* DispatcherServletRegistrationBean
* ὫdispatcherServletעᵽservlet
*/
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class,
name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties,
ObjectProvider<MultipartConfigElement> multipartConfig) {
// DispatcherServletRegistrationBeanὫdispatcherServletעᵽservlet
DispatcherServletRegistrationBean registration =
new DispatcherServletRegistrationBean(dispatcherServlet,
webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}
...
}
Ҫע 3 bean
dispatcherServletspringMvc ڣurl ɴ˽룬Ȼת requestMappingmultipartResolverļϴdispatcherServletRegistration dispatcherServlet עᣬὫ dispatcherServlet עᵽ servlet У springboot ע servlet ݣԲο springboot web Ӧ֮ servlet עWebMvcAutoConfigurationWebMvcAutoConfiguration:
@Configuration(proxyBeanMethods = false)
...
// ûԶWebMvc࣬ʹñ
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
...
public class WebMvcAutoConfiguration {
...
}
WebMvcAutoConfiguration иעҪע£
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
д WebMvcAutoConfiguration ֻ WebMvcConfigurationSupport ͵ bean ʱŻԶװ䡣
WebMvcConfigurationSupport Ǹɶأ springmvc demo @EnableWebMvc עһУᵽ springMvc ַʽ
@EnableWebMvc עWebMvcConfigurationSupportַն spring Ϊ WebMvcConfigurationSupport bean springboot ĿУǽֲ֮һô WebMvcConfigurationSupport``WebMvcAutoConfiguration ԶװͲִˡ
WebMvcAutoConfiguration װ bean
WebMvcAutoConfigurationAdapterWebMvcAutoConfigurationAdapter WebMvcAutoConfiguration ڲ࣬£
@Configuration(proxyBeanMethods = false)
// EnableWebMvcConfiguration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
...
}
ʵ WebMvcConfigurer EnableWebMvcConfiguration``WebMvcConfigurer springMvc ãֻҪджӦķɣEnableWebMvcConfiguration webMvc áҲ WebMvcAutoConfiguration ڲ࣬ɶ
@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
implements ResourceLoaderAware {
...
}
Կ DelegatingWebMvcConfiguration ࣬ DelegatingWebMvcConfiguration ǸɶأҲĶ壺
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
...
}
DelegatingWebMvcConfiguration springMvc ṩģԿʵ WebMvcConfigurationSupportˣspringboot ͨ @Import(EnableWebMvcConfiguration.class) ķʽ spring WebMvcConfigurationSupport ͵ bean
ʵϣDelegatingWebMvcConfiguration @EnableWebMvc bean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// DelegatingWebMvcConfiguration
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
...
}
springbot ֱ DelegatingWebMvcConfiguration EnableWebMvcConfigurationȻһЩԶõġ
EnableWebMvcConfiguration Щɶһٷ WebMvcAutoConfigurationAdapter bean
/**
* http Ϣת.
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable(
(customConverters) -> converters.addAll(customConverters.getConverters()));
}
/**
* ͼ.
*/
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;
}
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
/**
* ʻ.
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
/**
* ̬Դӳ
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
// ӳwebjars
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache()
.getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
// ӳ侲̬Դ·
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
// staticLocations ĬΪ classpath:[/META-INF/resources/,
// /resources/, /static/, /public/]
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
ԿWebMvcAutoConfigurationAdapter bean:
ص httpϢתʹ springMvc ʱͨ Controller еķϱ @ResponseBodyزͻתΪ json httpϢתĹˡspringboot Ĭϵ jaon jacksonʵ JacksonAutoConfiguration УװΪ HttpMessageConverter Ĵ JacksonHttpMessageConvertersConfigurationͲչˡ
ķУγ WebMvcProperties ãǸɶ
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
...
}
ԣǸ ԿǰΪ spring.mvcֵ֧£
EnableWebMvcConfigurationEnableWebMvcConfiguration Զã
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
implements ResourceLoaderAware {
/**
*
*/
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager")
ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(
contentNegotiationManager, conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
/**
* ·ӳ
*/
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager")
ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
/**
* ӭҳ
*/
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ApplicationContext applicationContext,
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext,
getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(
mvcConversionService, mvcResourceUrlProvider));
return welcomePageHandlerMapping;
}
/**
* mvcãڸʽĴ
*/
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService
= new WebConversionService(this.mvcProperties.getDateFormat());
addFormatters(conversionService);
return conversionService;
}
/**
* У
*/
@Bean
@Override
public Validator mvcValidator() {
if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
return super.mvcValidator();
}
return ValidatorAdapter.get(getApplicationContext(), getValidator());
}
/**
* 쳣
*/
@Override
protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
if (this.mvcRegistrations != null
&& this.mvcRegistrations.getExceptionHandlerExceptionResolver() != null) {
return this.mvcRegistrations.getExceptionHandlerExceptionResolver();
}
return super.createExceptionHandlerExceptionResolver();
}
@Override
protected void extendHandlerExceptionResolvers(
List<HandlerExceptionResolver> exceptionResolvers) {
super.extendHandlerExceptionResolvers(exceptionResolvers);
if (this.mvcProperties.isLogResolvedException()) {
for (HandlerExceptionResolver resolver : exceptionResolvers) {
if (resolver instanceof AbstractHandlerExceptionResolver) {
((AbstractHandlerExceptionResolver) resolver).setWarnLogCategory(
resolver.getClass().getName());
}
}
}
}
...
}
ԭ springMvc·ӳ䡢У顢쳣ȡ
webMvc װʱװ ServletWebServerFactoryAutoConfigurationװ DispatcherServletAutoConfigurationװ WebMvcAutoConfigurationServletWebServerFactoryAutoConfiguration servlet װ䣬DispatcherServletAutoConfiguration DispatcherServlet װ䣬WebMvcAutoConfiguration webMvc Ϣתͼ̬ԴӳȣװWebMvcConfigurationSupport WebMvcAutoConfiguration װִservlet servlet ΪǰwebMvc spring.mvc ΪǰǿļһΪ application.properties/application.ymlнԭӣhttps://my.oschina.net/funcy/blog/4921595 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע