SpringBoot中SpringMVC自动配置源码学习笔记

SpringMVC自动配置

	源码:
	@Configuration
	@ConditionalOnWebApplication(type = Type.SERVLET)
	@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
	@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
	@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
	@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
			ValidationAutoConfiguration.class })
	public class WebMvcAutoConfiguration {

		@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;
		}

ContentNegotiatingViewResolver//组合所有的视图解析器的

			源码:
			//视图解析器(根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
			public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {

				@Override
				@Nullable
				public View resolveViewName(String viewName, Locale locale) throws Exception {
					RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
					Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
					List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
					if (requestedMediaTypes != null) {
						//获取候选视图对象
						List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
						//选择最适合的视图对象
						View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
						if (bestView != null) {
							return bestView;
						}
					}
					
					private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
						List<View> candidateViews = new ArrayList<>();
						if (this.viewResolvers != null) {
							Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
							//把所有视图解析器拿来,解析
							for (ViewResolver viewResolver : this.viewResolvers) {
								View view = viewResolver.resolveViewName(viewName, locale);
								if (view != null) {
									candidateViews.add(view);
								}
								for (MediaType requestedMediaType : requestedMediaTypes) {
									List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
									for (String extension : extensions) {
										String viewNameWithExtension = viewName + '.' + extension;
										view = viewResolver.resolveViewName(viewNameWithExtension, locale);
										if (view != null) {
											candidateViews.add(view);
										}
									}
								}
							}
						}
						if (!CollectionUtils.isEmpty(this.defaultViews)) {
							candidateViews.addAll(this.defaultViews);
						}
						return candidateViews;
					}
				}
			}	
			
		//注册国际化功能
		@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
		protected void initServletContext(ServletContext servletContext) {
			//从容器中获取所有的视图解析器
			Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), ViewResolver.class).values();
			//把这个解析器作为要组合的所有的视图解析器
			if (this.viewResolvers == null) {
				this.viewResolvers = new ArrayList<>(matchingBeans.size());
				for (ViewResolver viewResolver : matchingBeans) {
					if (this != viewResolver) {
						this.viewResolvers.add(viewResolver);
					}
				}
			}
			else {
				for (int i = 0; i < this.viewResolvers.size(); i++) {
					ViewResolver vr = this.viewResolvers.get(i);
					if (matchingBeans.contains(vr)) {
						continue;
					}
					String name = vr.getClass().getName() + i;
					obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
				}
			}
			AnnotationAwareOrderComparator.sort(this.viewResolvers);
			this.cnmFactoryBean.setServletContext(servletContext);
		}
		
		//添加格式化器,自己添加的格式化器转换器,我们只需要放在容器中即可
		@Override
		public void addFormatters(FormatterRegistry registry) {
			//Converter转换器,类型转换
			for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
				registry.addConverter(converter);
			}
			for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
				registry.addConverter(converter);
			}
			//Formatter格式化器,日期
			for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
				registry.addFormatter(formatter);
			}
		}
		private <T> Collection<T> getBeansOfType(Class<T> type) {
			//从容器beanFactory中获取所有的Converter
			return this.beanFactory.getBeansOfType(type).values();
		}
		
		@Configuration
		@Import(EnableWebMvcConfiguration.class)
		@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
		@Order(0)
		public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
		
			private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
			
			//是HttpMessageConverters从容器中确定;获取所有的HttpMessageConverter
			public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
				ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
				ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
				this.resourceProperties = resourceProperties;
				this.mvcProperties = mvcProperties;
				this.beanFactory = beanFactory;
				this.messageConvertersProvider = messageConvertersProvider;
				this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
			}
		}	

HttpMessageConverters//是HttpMessageConverters从容器中确定;获取所有的HttpMessageConverter

			源码:
			public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> {
				
				public HttpMessageConverters(Collection<HttpMessageConverter<?>> additionalConverters) {
					this(true, additionalConverters);
				}
			}
		
		
		//消息解析,从配置类里拿配置
		@Override
		public MessageCodesResolver getMessageCodesResolver() {
			if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
				DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
				resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
				return resolver;
			}
			return null;
		}

getMessageCodesResolverFormat()

			源码:
			@ConfigurationProperties(prefix = "spring.mvc")
			public class WebMvcProperties {
			
				private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
				
				public DefaultMessageCodesResolver.Format getMessageCodesResolverFormat() {
					return this.messageCodesResolverFormat;
				}
			}

DefaultMessageCodesResolver

				源码:
				@SuppressWarnings("serial")
				public class DefaultMessageCodesResolver implements MessageCodesResolver, Serializable {
					
					//定义错误代码生成规则
					public enum Format implements MessageCodeFormatter {
						/**
						 * Prefix the error code at the beginning of the generated message code. e.g.:
						 * {@code errorCode + "." + object name + "." + field}
						 * 第一种规则(错误代码,对象名,属性名)
						 */					
						PREFIX_ERROR_CODE {
							@Override
							public String format(String errorCode, @Nullable String objectName, @Nullable String field) {
								return toDelimitedString(errorCode, objectName, field);
							}
						},

						/**
						 * Postfix the error code at the end of the generated message code. e.g.:
						 * {@code object name + "." + field + "." + errorCode}
						 * 第二种规则(对象名,属性名,错误代码)
						 */
						POSTFIX_ERROR_CODE {
							@Override
							public String format(String errorCode, @Nullable String objectName, @Nullable String field) {
								return toDelimitedString(objectName, field, errorCode);
							}
						};

						/**
						 * Concatenate the given elements, delimiting each with
						 * {@link DefaultMessageCodesResolver#CODE_SEPARATOR}, skipping zero-length or
						 * null elements altogether.
						 */
						public static String toDelimitedString(String... elements) {
							StringBuilder rtn = new StringBuilder();
							for (String element : elements) {
								if (StringUtils.hasLength(element)) {
									rtn.append(rtn.length() == 0 ? "" : CODE_SEPARATOR);
									rtn.append(element);
								}
							}
							return rtn.toString();
						}
					}			
				}
		//可以配置一个ConfigurableWebBindingInitializer来替换默认的(添加到容器中)
		@Override
		protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
			try {
				return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
			}
			catch (NoSuchBeanDefinitionException ex) {
				return super.getConfigurableWebBindingInitializer();
			}
		}

getConfigurableWebBindingInitializer()

			源码:
			//初始化web数据绑定器(WebDataBinder)的,把请求数据绑定到哪,比如到JavaBean
			protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
				ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
				initializer.setConversionService(mvcConversionService());
				initializer.setValidator(mvcValidator());
				MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
				if (messageCodesResolver != null) {
					initializer.setMessageCodesResolver(messageCodesResolver);
				}
				return initializer;
			}

ConfigurableWebBindingInitializer

				源码:
				//初始化web数据绑定器
				public class ConfigurableWebBindingInitializer implements org.springframework.web.bind.support.WebBindingInitializer {
					@Override
					public void initBinder(WebDataBinder binder) {
						binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
						if (this.directFieldAccess) {
							binder.initDirectFieldAccess();
						}
						if (this.messageCodesResolver != null) {
							binder.setMessageCodesResolver(this.messageCodesResolver);
						}
						if (this.bindingErrorProcessor != null) {
							binder.setBindingErrorProcessor(this.bindingErrorProcessor);
						}
						if (this.validator != null && binder.getTarget() != null &&
								this.validator.supports(binder.getTarget().getClass())) {
							binder.setValidator(this.validator);
						}
						if (this.conversionService != null) {
							binder.setConversionService(this.conversionService);
						}
						if (this.propertyEditorRegistrars != null) {
							for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
								propertyEditorRegistrar.registerCustomEditors(binder);
							}
						}
					}			
				}
	}

DispatcherServlet

		源码:
		@SuppressWarnings("serial")
		public class DispatcherServlet extends FrameworkServlet {
			
			//所有请求进来调用该方法
			protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
				HttpServletRequest processedRequest = request;
				HandlerExecutionChain mappedHandler = null;
				boolean multipartRequestParsed = false;

				WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

				try {
					ModelAndView mv = null;
					Exception dispatchException = null;

					try {
						processedRequest = checkMultipart(request);
						multipartRequestParsed = (processedRequest != request);

						// Determine handler for the current request.
						mappedHandler = getHandler(processedRequest);
						if (mappedHandler == null) {
							noHandlerFound(processedRequest, response);
							return;
						}

						// Determine handler adapter for the current request.
						HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

						// Process last-modified header, if supported by the handler.
						String method = request.getMethod();
						boolean isGet = "GET".equals(method);
						if (isGet || "HEAD".equals(method)) {
							long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
							if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
								return;
							}
						}

						if (!mappedHandler.applyPreHandle(processedRequest, response)) {
							return;
						}

						// Actually invoke the handler.
						mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

						if (asyncManager.isConcurrentHandlingStarted()) {
							return;
						}

						applyDefaultViewName(processedRequest, mv);
						mappedHandler.applyPostHandle(processedRequest, response, mv);
					}
					catch (Exception ex) {
						dispatchException = ex;
					}
					catch (Throwable err) {
						// As of 4.3, we're processing Errors thrown from handler methods as well,
						// making them available for @ExceptionHandler methods and other scenarios.
						dispatchException = new NestedServletException("Handler dispatch failed", err);
					}
					processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
				}
				catch (Exception ex) {
					triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
				}
				catch (Throwable err) {
					triggerAfterCompletion(processedRequest, response, mappedHandler,
							new NestedServletException("Handler processing failed", err));
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						// Instead of postHandle and afterCompletion
						if (mappedHandler != null) {
							mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
						}
					}
					else {
						// Clean up any resources used by a multipart request.
						if (multipartRequestParsed) {
							cleanupMultipart(processedRequest);
						}
					}
				}
			}				
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值