WebMvcAutoConfiguration

WebMvcAutoConfiguration 是Spring boot针对Web MVC的自动配置机制。

//表明是一个配置类
@Configuration(proxyBeanMethods = false)
//必须是SERVLET类型才会启用,引入web依赖后,默认是SERVLET类型
@ConditionalOnWebApplication(type = Type.SERVLET)
//必须有这三个类才会启用此配置类
@ConditionalOnClass({
    
     Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//没有WebMvcConfigurationSupport这个的时候才会启用此配置类。WebMvcConfigurationSupport通过 @EnableWebMvc可以引入
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
//指定加载顺序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
//在这三个配置生效之后才会加载此配置类
@AutoConfigureAfter({
    
     DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
    
}

这个配置类中主要有几个内部类
1.导入了两个组件

	//支持表单rest风格的请求,过滤器,对request进行封装,获取_method的value。实现表单rest
	@Bean
	@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
	@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
	public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
    
    
		return new OrderedHiddenHttpMethodFilter();
	}

	@Bean
	@ConditionalOnMissingBean(FormContentFilter.class)
	@ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true)
	public OrderedFormContentFilter formContentFilter() {
    
    
		return new OrderedFormContentFilter();
	}

2.一个成员方法

	static String[] getResourceLocations(String[] staticLocations) {
    
    
		String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
		System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
		System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
		return locations;
	}

3.WebMvcAutoConfigurationAdapter静态内部类 实现了WebMvcConfigurer接口,要重写某些方法。

注意,这里导入了配置类 EnableWebMvcConfiguration, 它是 DelegatingWebMvcConfiguration 的子类,
EnableWebMvcConfiguration + DelegatingWebMvcConfiguration 用于定义一些MVC使用的bean组件到容器,
WebMvcAutoConfigurationAdapter 的目的是定义一些MVC使用的bean到容器,但更主要目的是自身作为一个WebMvcConfigurer 配置bean , 最终被 DelegatingWebMvcConfiguration 用于配置Spring MVC运行时要使用的bean组件

代码有点多----

	@Configuration(proxyBeanMethods = false)
	//导入EnableWebMvcConfiguration组件
	@Import(EnableWebMvcConfiguration.class)
	//绑定这两个配置类,并加载到spring容器中
	@EnableConfigurationProperties({
    
     WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer{
    
    
		private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);

		private final ResourceProperties resourceProperties;

		private final WebMvcProperties mvcProperties;

		private final ListableBeanFactory beanFactory;

		private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;

		final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
		//有参构造函数 这些全要从容器中拿
		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();
		}
		//重写方法 给成员变量messageConvertersProvider赋值
		@Override
		public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    
    
			this.messageConvertersProvider
					.ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters()));
		}
		//重写方法 关于异步请求的处理
		@Override
		public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    
    
			if (this.beanFactory.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {
    
    
				Object taskExecutor = this.beanFactory
						.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);
				if (taskExecutor instanceof AsyncTaskExecutor) {
    
    
					configurer.setTaskExecutor(((AsyncTaskExecutor) taskExecutor));
				}
			}
			Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();
			if (timeout != null) {
    
    
				configurer.setDefaultTimeout(timeout.toMillis());
			}
		}
		//路径匹配的 前缀之类的 默认没有
		@Override
		public void configurePathMatch(PathMatchConfigurer configurer) {
    
    
			configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
			configurer.setUseRegisteredSuffixPatternMatch(
					this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
		}
		//配置内容协商
		@Override
		public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    
    
			WebMvcProperties.Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();
			configurer.favorPathExtension(contentnegotiation.isFavorPathExtension());
			configurer.favorParameter(contentnegotiation.isFavorParameter());
			if (contentnegotiation.getParameterName() != null) {
    
    
				configurer.parameterName(contentnegotiation.getParameterName());
			}
			Map<String, MediaType> mediaTypes = this.mvcProperties.getContentnegotiation().getMediaTypes();
			mediaTypes.forEach(configurer::mediaType);
		}
		//注入组件 和jsp有关的 支持了forward的jsp页面include功能和防止循环引用
		@Bean
		@ConditionalOnMissingBean
		public InternalResourceViewResolver defaultViewResolver() {
    
    
			InternalResourceViewResolver resolver = new InternalResourceViewResolver();
			resolver.setPrefix(this.mvcProperties.getView().getPrefix());
			resolver.setSuffix(this.mvcProperties.getView().getSuffix());
			return resolver;
		}
		//BeanNameViewResolver就是通过我们Controller返回的string 作为beanName去spring容器中获取View对象调用其render方法渲染数据
		@Bean
		@ConditionalOnBean(View.class)
		@ConditionalOnMissingBean
		public BeanNameViewResolver beanNameViewResolver() {
    
    
			BeanNameViewResolver resolver = new BeanNameViewResolver();
			resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
			return resolver;
		}
		//根据需求返回不同形式的页面 例如xml json 核心方法:resolveViewName()  getMediaTypes()
		@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));
			// ContentNegotiatingViewResolver uses all the other view resolvers to locate
			// a view so it should have a high precedence
			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 MessageCodesResolver getMessageCodesResolver() {
    
    
			if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
    
    
				DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
				resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
				return resolver;
			}
			return null;
		}
		//类型转换相关 如日期格式转换
		@Override
		public void addFormatters(FormatterRegistry registry) {
    
    
			ApplicationConversionService.addBeans(registry, this.beanFactory);
		}
		//定义静态资源访问路径  "classpath:/META-INF/resources/",
		//	"classpath:/resources/", "classpath:/static/", "classpath:/public/"
		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
			if (!this.resourceProperties.isAddMappings()) {
    
    
				logger.debug("Default resource handling disabled");
				return;
			}
			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)
						.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
						.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
			}
		}
		
		private Integer getSeconds(Duration cachePeriod) {
    
    
			return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
		}

		private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
    
    
			if (this.resourceHandlerRegistrationCustomizer != null) {
    
    
				this.resourceHandlerRegistrationCustomizer.customize(registration);
			}
		}
		//该过滤器将当前请求暴露到当前线程
		@Bean
		@ConditionalOnMissingBean({
    
     RequestContextListener.class, RequestContextFilter.class })
		@ConditionalOnMissingFilterBean(RequestContextFilter.class)
		public static RequestContextFilter requestContextFilter() {
    
    
			return new OrderedRequestContextFilter();
		}
	}

4.EnableWebMvcConfiguration静态内部类
代码有点长—

@Configuration(proxyBeanMethods = false)
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware{
    
    
		private final ResourceProperties resourceProperties;

		private final WebMvcProperties mvcProperties;

		private final ListableBeanFactory beanFactory;

		private final WebMvcRegistrations mvcRegistrations;

		private ResourceLoader resourceLoader;
		//有参构造
		public EnableWebMvcConfiguration(ResourceProperties resourceProperties,
				ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
				ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
    
    
			this.resourceProperties = resourceProperties;
			this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
			this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
			this.beanFactory = beanFactory;
		}
		//用于处理使用@RequestMapping注解修饰的方法。
		@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;
		}
		//用于处理使用@RequestMapping注解修饰的方法。
		@Override
		protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
    
    
			if (this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null) {
    
    
				return this.mvcRegistrations.getRequestMappingHandlerAdapter();
			}
			return super.createRequestMappingHandlerAdapter();
		}
		//决定用哪个controller处理 一共有5个,自动注入两个:requestMappingHandlerMapping和welcomePageHandlerMapping
		@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);
		}
		//欢迎页  index.html
		@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;
		}
		//根据配置类获取路径
		private Optional<Resource> getWelcomePage() {
    
    
			String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
			return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
		}
		//
		private Resource getIndexHtml(String location) {
    
    
			return this.resourceLoader.getResource(location + "index.html");
		}
		//
		private boolean isReadable(Resource resource) {
    
    
			try {
    
    
				return resource.exists() && (resource.getURL() != null);
			}
			catch (Exception ex) {
    
    
				return false;
			}
		}

		//默认日期格式
		@Bean
		@Override
		public FormattingConversionService mvcConversionService() {
    
    
			WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
			addFormatters(conversionService);
			return conversionService;
		}
		//表单验证 JSR303
		@Bean
		@Override
		public Validator mvcValidator() {
    
    
			if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
    
    
				return super.mvcValidator();
			}
			return ValidatorAdapter.get(getApplicationContext(), getValidator());
		}

		@Override
		protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    
    
			if (this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerMapping() != null) {
    
    
				return this.mvcRegistrations.getRequestMappingHandlerMapping();
			}
			return super.createRequestMappingHandlerMapping();
		}
		//数据绑定 例如前端传过来字符串 可以配置解析成日期
		@Override
		protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(
				FormattingConversionService mvcConversionService, Validator mvcValidator) {
    
    
			try {
    
    
				return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
			}
			catch (NoSuchBeanDefinitionException ex) {
    
    
				return super.getConfigurableWebBindingInitializer(mvcConversionService, mvcValidator);
			}
		}
		//异常处理
		@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());
					}
				}
			}
		}
		//内容协商管理器
		@Bean
		@Override
		public ContentNegotiationManager mvcContentNegotiationManager() {
    
    
			ContentNegotiationManager manager = super.mvcContentNegotiationManager();
			List<ContentNegotiationStrategy> strategies = manager.getStrategies();
			ListIterator<ContentNegotiationStrategy> iterator = strategies.listIterator();
			while (iterator.hasNext()) {
    
    
				ContentNegotiationStrategy strategy = iterator.next();
				if (strategy instanceof PathExtensionContentNegotiationStrategy) {
    
    
					iterator.set(new OptionalPathExtensionContentNegotiationStrategy(strategy));
				}
			}
			return manager;
		}

		@Override
		public void setResourceLoader(ResourceLoader resourceLoader) {
    
    
			this.resourceLoader = resourceLoader;
		}	
	}

猜你喜欢

转载自blog.csdn.net/weixin_46666822/article/details/124732350