Spring MVC之自动化配置核心类WebMvcAutoConfiguration

@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 {
    
    

}

1、WebMvcAutoConfigurationAdapter

@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({
    
     WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
    
    
	...
	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();
	}
	...
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    
    
		this.messageConvertersProvider
				.ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters()));
	}
	...
	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
    
    
		configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
		configurer.setUseRegisteredSuffixPatternMatch(
				this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
	}
	...
	@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;
	}
	...
	private <T> Collection<T> getBeansOfType(Class<T> type) {
    
    
		return this.beanFactory.getBeansOfType(type).values();
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
		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));
		}
	}
	...
	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;
	}
	...
	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();
	}
	...
}

2、EnableWebMvcConfiguration

等价于 @EnableWebMvc 注解。

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
    
    

	private final WebMvcProperties mvcProperties;

	private final ListableBeanFactory beanFactory;

	private final WebMvcRegistrations mvcRegistrations;

	public EnableWebMvcConfiguration(ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
			ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
    
    
		this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
		this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
		this.beanFactory = beanFactory;
	}

	@Bean
	@Override
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    
    
		RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
		adapter.setIgnoreDefaultModelOnRedirect(
				this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
		return adapter;
	}

	@Override
	protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
    
    
		if (this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null) {
    
    
			return this.mvcRegistrations.getRequestMappingHandlerAdapter();
		}
		return super.createRequestMappingHandlerAdapter();
	}

	@Bean
	@Primary
	@Override
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    
    
		// Must be @Primary for MvcUriComponentsBuilder to work
		return super.requestMappingHandlerMapping();//WebMvcConfigurationSupport#requestMappingHandlerMapping
	}
	...
	@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();
		}
		//WebMvcConfigurationSupport#createRequestMappingHandlerMapping
		return super.createRequestMappingHandlerMapping();
	}

	@Override
	protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
    
    
		try {
    
    
			return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
		}
		catch (NoSuchBeanDefinitionException ex) {
    
    
			return super.getConfigurableWebBindingInitializer();
		}
	}
	...
	@Override
	protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    
    
		super.configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
    
    
			addDefaultHandlerExceptionResolvers(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;
	}
}

DelegatingWebMvcConfiguration是WebMvcConfigurationSupport的子类。

3、WebMvcConfigurationSupport

这个类的作用是通过 Java Config配置方式给服务提供MVC功能。核心功能是初始化SpringMVC中九大组件之HandlerMapping、HandlerAdapter。

public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    
    
	//EnableWebMvcConfiguration#createRequestMappingHandlerMapping
	RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
	mapping.setOrder(0);
	mapping.setInterceptors(getInterceptors());//用户自定义拦截器
	mapping.setContentNegotiationManager(mvcContentNegotiationManager());
	mapping.setCorsConfigurations(getCorsConfigurations());

	PathMatchConfigurer configurer = getPathMatchConfigurer();

	Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
	if (useSuffixPatternMatch != null) {
    
    
		mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
	}
	Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
	if (useRegisteredSuffixPatternMatch != null) {
    
    
		mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
	}
	Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
	if (useTrailingSlashMatch != null) {
    
    
		mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
	}

	UrlPathHelper pathHelper = configurer.getUrlPathHelper();
	if (pathHelper != null) {
    
    
		mapping.setUrlPathHelper(pathHelper);
	}
	PathMatcher pathMatcher = configurer.getPathMatcher();
	if (pathMatcher != null) {
    
    
		mapping.setPathMatcher(pathMatcher);
	}
	Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
	if (pathPrefixes != null) {
    
    
		mapping.setPathPrefixes(pathPrefixes);
	}
	return mapping;
}
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
    
    
	return new RequestMappingHandlerMapping();
}

3.1、RequestMappingHandlerMapping

RequestMappingHandlerMapping在初始化过程中存在拦截器、路由匹配规则等功能的初始化。

4、EnableWebMvc注解

该注解通过@Import生成 WebMvcConfigurationSupport 类的子类 DelegatingWebMvcConfiguration。
首先该注解的存在将导致WebMvcAutoConfiguration无法自动初始化,也即意味着WebMvcAutoConfiguration类中初始化RequestMappingHandlerMapping等SpringMVC组件的功能需要自己实现。

猜你喜欢

转载自blog.csdn.net/qq_36851469/article/details/128179137