SpringMVC之@EnableWebMvc源码分析

前言

本文重点研究@EnableWebMvc的作用及其源码

一、源码研究

@EnableWebMvc源码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

从这可以看出@EnableWebMvc注解的作用是注册DelegatingWebMvcConfiguration类,注意他是一个配置类

配置 proxyBeanMethods 属性后,配置类不会被代理了。主要是为了提高性能,如果你的 @Bean 方法之间没有调用关系的话可以把 proxyBeanMethods 设置为 false。否则,方法内部引用的类生产的类和 Spring 容器中类是两个类。

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
   
	@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
		}
	}
    //忽略代码。。。。。

DelegatingWebMvcConfiguration有2个作用:
1、扫描容器中的WebMvcConfigurer,放到WebMvcConfigurerComposite
2、其主要实现代码都在其父类WebMvcConfigurationSupport中,他将WebMvcConfigurerWebMvcConfigurationSupport联系起来了

至于怎么联系,这边以其addFormatters方法作为案例说明:

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    @Override
	protected void addFormatters(FormatterRegistry registry) {
	    //循环遍历configurers中WebMvcConfigurer到addFormatters方法
		this.configurers.addFormatters(registry);
	}

DelegatingWebMvcConfiguration重写类其父类的addFormatters方法

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    @Bean
	public FormattingConversionService mvcConversionService() {
		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		addFormatters(conversionService);
		return conversionService;
	}
    //子类DelegatingWebMvcConfiguration重写
	protected void addFormatters(FormatterRegistry registry) {
	}

所以我们可以通过继承WebMvcConfigurer重写其addFormatters方法,来添加新的Converter

@ComponentScan(value = "clyu", useDefaultFilters = false,
               includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, 
@Configuration
@EnableWebMvc
public class MyWebMvcConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
                registry.addConverter();
        }
}

这也是WebMvcConfigurer为什么要加@EnableWebMvc,才能生效的原因

二、注册方法研究

1、注册HandlerMapping

a、RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
        //直接new
		RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
		mapping.setOrder(0);
		//配置Interceptor
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setContentNegotiationManager(contentNegotiationManager);
		//配置CorsConfiguration
		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;
	}
b、BeanNameUrlHandlerMapping
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping(
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setCorsConfigurations(getCorsConfigurations());
		return mapping;
	}
c、RouterFunctionMapping
@Bean
public RouterFunctionMapping routerFunctionMapping(
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		RouterFunctionMapping mapping = new RouterFunctionMapping();
		mapping.setOrder(3);
		mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		mapping.setCorsConfigurations(getCorsConfigurations());
		mapping.setMessageConverters(getMessageConverters());
		return mapping;
}
d、SimpleUrlHandlerMapping
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
@Bean
public HandlerMapping defaultServletHandlerMapping() {
		Assert.state(this.servletContext != null, "No ServletContext set");
		DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
		configureDefaultServletHandling(configurer);
		return configurer.buildHandlerMapping();
}
@Nullable
protected SimpleUrlHandlerMapping buildHandlerMapping() {
		if (this.handler == null) {
			return null;
		}
      return new SimpleUrlHandlerMapping(Collections.singletonMap("/**", this.handler), Ordered.LOWEST_PRECEDENCE);
}
protected void addViewControllers(ViewControllerRegistry registry) {
	}

@Bean
	@Nullable
	public HandlerMapping viewControllerHandlerMapping(
			@Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
			@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
		ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
		addViewControllers(registry);

		AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
		if (handlerMapping == null) {
			return null;
		}
		handlerMapping.setPathMatcher(pathMatcher);
		handlerMapping.setUrlPathHelper(urlPathHelper);
		handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
		return handlerMapping;
	}
    @Nullable
	protected SimpleUrlHandlerMapping buildHandlerMapping() {
		if (this.registrations.isEmpty() && this.redirectRegistrations.isEmpty()) {
			return null;
		}

		Map<String, Object> urlMap = new LinkedHashMap<>();
		for (ViewControllerRegistration registration : this.registrations) {
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}
		for (RedirectViewControllerRegistration registration : this.redirectRegistrations) {
			urlMap.put(registration.getUrlPath(), registration.getViewController());
		}

		return new SimpleUrlHandlerMapping(urlMap, this.order);
	}
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
	}
@Bean
	@Nullable
	public HandlerMapping resourceHandlerMapping(
			@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
			@Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

		Assert.state(this.applicationContext != null, "No ApplicationContext set");
		Assert.state(this.servletContext != null, "No ServletContext set");

		ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
				this.servletContext, contentNegotiationManager, urlPathHelper);
		addResourceHandlers(registry);
		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
		if (handlerMapping == null) {
			return null;
		}
		handlerMapping.setPathMatcher(pathMatcher);
		handlerMapping.setUrlPathHelper(urlPathHelper);
		handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
		return handlerMapping;
	}
@Nullable
	protected AbstractHandlerMapping getHandlerMapping() {
		if (this.registrations.isEmpty()) {
			return null;
		}

		Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<>();
		for (ResourceHandlerRegistration registration : this.registrations) {
			for (String pathPattern : registration.getPathPatterns()) {
				ResourceHttpRequestHandler handler = registration.getRequestHandler();
				if (this.pathHelper != null) {
					handler.setUrlPathHelper(this.pathHelper);
				}
				if (this.contentNegotiationManager != null) {
					handler.setContentNegotiationManager(this.contentNegotiationManager);
				}
				handler.setServletContext(this.servletContext);
				handler.setApplicationContext(this.applicationContext);
				try {
					handler.afterPropertiesSet();
				}
				catch (Throwable ex) {
					throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex);
				}
				urlMap.put(pathPattern, handler);
			}
		}

		return new SimpleUrlHandlerMapping(urlMap, this.order);
	}

2、注册HandlerAdapter

a、RequestMappingHandlerAdapter
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcValidator") Validator validator) {
        //直接new个RequestMappingHandlerAdapter
		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
		adapter.setContentNegotiationManager(contentNegotiationManager);
		adapter.setMessageConverters(getMessageConverters());
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

		if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}

		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

		return adapter;
	}
b、HttpRequestHandlerAdapter
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
        return new HttpRequestHandlerAdapter();
}

c、SimpleControllerHandlerAdapter
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
        return new SimpleControllerHandlerAdapter();
}
d、HandlerFunctionAdapter
public HandlerFunctionAdapter handlerFunctionAdapter() {
		return new HandlerFunctionAdapter();
}

3、注册HandlerExceptionResolver

//注册HandlerExceptionResolver,这个exceptionResolvers是为空的
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {}
//添加HandlerExceptionResolver,这个exceptionResolvers是有值的
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {}
@Bean
public HandlerExceptionResolver handlerExceptionResolver(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
		//模版方法,操作exceptionResolvers
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
		    //如果我们没有配置HandlerExceptionResolver,那么就注册默认的
			addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
		}
		//模版方法,操作exceptionResolvers
		extendHandlerExceptionResolvers(exceptionResolvers);
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}
	
   protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,
                                                             ContentNegotiationManager mvcContentNegotiationManager) {

        //直接new
        ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
        exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
        //添加MessageConverters
        exceptionHandlerResolver.setMessageConverters(getMessageConverters());
        //添加ArgumentResolvers
        exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
        //添加ReturnValueHandlers
        exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
        //如果com.fasterxml.jackson.databind.ObjectMapper", classLoader) 和 com.fasterxml.jackson.core.JsonGenerator 有
        if (jackson2Present) {
            exceptionHandlerResolver.setResponseBodyAdvice(
                    Collections.singletonList(new JsonViewResponseBodyAdvice()));
        }
        if (this.applicationContext != null) {
            exceptionHandlerResolver.setApplicationContext(this.applicationContext);
        }
        exceptionHandlerResolver.afterPropertiesSet();
        exceptionResolvers.add(exceptionHandlerResolver);

        ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
        responseStatusResolver.setMessageSource(this.applicationContext);
        exceptionResolvers.add(responseStatusResolver);
        exceptionResolvers.add(new DefaultHandlerExceptionResolver());
    }

4、注册ViewResolver

protected void configureViewResolvers(ViewResolverRegistry registry) {}
@Bean
public ViewResolver mvcViewResolver(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
        ViewResolverRegistry registry =
                new ViewResolverRegistry(contentNegotiationManager, this.applicationContext);
        configureViewResolvers(registry);

        if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
            String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext, ViewResolver.class, true, false);
            if (names.length == 1) {
                registry.getViewResolvers().add(new InternalResourceViewResolver());
            }
        }
        ViewResolverComposite composite = new ViewResolverComposite();
        composite.setOrder(registry.getOrder());
        composite.setViewResolvers(registry.getViewResolvers());
        if (this.applicationContext != null) {
            composite.setApplicationContext(this.applicationContext);
        }
        if (this.servletContext != null) {
            composite.setServletContext(this.servletContext);
        }
        return composite;
}

5、注册Validator

public Validator getValidator() {return null;}
@Bean
public Validator mvcValidator() {
        Validator validator = getValidator();
        if (validator == null) {
            if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
                Class<?> clazz;
                try {
                    String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
                    clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
                }
                catch (ClassNotFoundException | LinkageError ex) {
                    throw new BeanInitializationException("Failed to resolve default validator class", ex);
                }
                validator = (Validator) BeanUtils.instantiateClass(clazz);
            }
            else {
                validator = new NoOpValidator();
            }
        }
        return validator;
}

6、注册FormattingConversionService

protected void addFormatters(FormatterRegistry registry) {}
@Bean
public FormattingConversionService mvcConversionService() {
        FormattingConversionService conversionService = new DefaultFormattingConversionService();
        addFormatters(conversionService);
        return conversionService;
}

7、注册PathMatcher和UrlPathHelper

protected void configurePathMatch(PathMatchConfigurer configurer) {}
protected PathMatchConfigurer getPathMatchConfigurer() {
		if (this.pathMatchConfigurer == null) {
			this.pathMatchConfigurer = new PathMatchConfigurer();
			configurePathMatch(this.pathMatchConfigurer);
		}
		return this.pathMatchConfigurer;
}

@Bean
public ResourceUrlProvider mvcResourceUrlProvider() {
        ResourceUrlProvider urlProvider = new ResourceUrlProvider();
        UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
        if (pathHelper != null) {
            urlProvider.setUrlPathHelper(pathHelper);
        }
        PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
        if (pathMatcher != null) {
            urlProvider.setPathMatcher(pathMatcher);
        }
        return urlProvider;
}

@Bean
public PathMatcher mvcPathMatcher() {
		PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
		return (pathMatcher != null ? pathMatcher : new AntPathMatcher());
}

	
@Bean
public UrlPathHelper mvcUrlPathHelper() {
		UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
		return (pathHelper != null ? pathHelper : new UrlPathHelper());
}

8、 配置Interceptor

protected void addInterceptors(InterceptorRegistry registry) {}
protected final Object[] getInterceptors(FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
		if (this.interceptors == null) {
			InterceptorRegistry registry = new InterceptorRegistry();
			addInterceptors(registry);
			registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
			registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
			this.interceptors = registry.getInterceptors();
		}
		return this.interceptors.toArray();
}

9、 配置CorsConfiguration

protected void addCorsMappings(CorsRegistry registry) {}
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
		if (this.corsConfigurations == null) {
			CorsRegistry registry = new CorsRegistry();
			addCorsMappings(registry);
			this.corsConfigurations = registry.getCorsConfigurations();
		}
		return this.corsConfigurations;
	}

10、配置MessageConverters

protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
protected final List<HttpMessageConverter<?>> getMessageConverters() {
		if (this.messageConverters == null) {
			this.messageConverters = new ArrayList<>();
			configureMessageConverters(this.messageConverters);
			if (this.messageConverters.isEmpty()) {
			    
				addDefaultHttpMessageConverters(this.messageConverters);
			}
			extendMessageConverters(this.messageConverters);
		}
		return this.messageConverters;
	}   

addDefaultHttpMessageConverters逻辑如下

1、先添加 ByteArrayHttpMessageConverterStringHttpMessageConverterResourceHttpMessageConverterResourceRegionHttpMessageConverterSourceHttpMessageConverterAllEncompassingFormHttpMessageConverter
2、判断 com.rometools.rome.feed.WireFeed 是否存在,如果在添加 AtomFeedHttpMessageConverterRssChannelHttpMessageConverter
3、判断com.fasterxml.jackson.dataformat.xml.XmlMappe是否存在,如果在添加 MappingJackson2XmlHttpMessageConverter
4、判断com.fasterxml.jackson.databind.ObjectMappercom.fasterxml.jackson.core.JsonGenerator 是否存在,如果在添加MappingJackson2HttpMessageConverter
5、判断javax.json.bind.Jsonb是否存在,如果在添加 JsonbHttpMessageConverter
6、判断com.google.gson.Gson是否存在,如果在添加 GsonHttpMessageConverter
7、判断com.fasterxml.jackson.dataformat.smile.SmileFactory是否存在,如果在添加 MappingJackson2SmileHttpMessageConverter
8、判断com.fasterxml.jackson.dataformat.cbor.CBORFactory是否存在,如果在添加 MappingJackson2CborHttpMessageConverter

11、配置MessageCodesResolver

protected MessageCodesResolver getMessageCodesResolver() {return null;}
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(
			FormattingConversionService mvcConversionService, Validator mvcValidator) {

		ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
		initializer.setConversionService(mvcConversionService);
		initializer.setValidator(mvcValidator);
		MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
		if (messageCodesResolver != null) {
			initializer.setMessageCodesResolver(messageCodesResolver);
		}
		return initializer;
	}

12、配置MessageCodesResolver

protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {}
protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
		if (this.argumentResolvers == null) {
			this.argumentResolvers = new ArrayList<>();
			addArgumentResolvers(this.argumentResolvers);
		}
		return this.argumentResolvers;
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值