
1. WebMvcConfigurationSupport 类
WebMvcConfigurationSupport 类提供了对 MVC 的配置支持;
1.1 变量
1.1.1 静态变量
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
static {
ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}
}
WebMvcConfigurationSupport 类中静态变量有 8 个,用于检测当前可用的序列化/反序列化库:其中 romePresent 属性通过检测 com.rometools.rome.feed.WireFeed 类是否存在来检测 ROME 库(RSS/Atom 订阅处理)是否存在,jaxb2Present 通过 javax.xml.bind.Binder 类检测 JAXB 库(XML绑定标准(JavaEE 标准)),jackson2Present 同时检查 com.fasterxml.jackson.databind.ObjectMapper 与 com.fasterxml.jackson.core.JsonGenerator 类来判断是否引入了 Jackson JSON 库(JSON 核心处理库),jackson2XmlPresent 通过 com.fasterxml.jackson.dataformat.xml.XmlMapper 类检测 Jackson XML 库(XML处理扩展),jackson2SmilePresent 通过 com.fasterxml.jackson.dataformat.smile.SmileFactory 类检测 Jackson Smile 库(二进制JSON格式处理),jackson2CborPresent 通过 com.fasterxml.jackson.dataformat.cbor.CBORFactory 类检测 Jackson CBOR 库(类似 MessagePack 的简洁二进制对象表示),gsonPresent 通过 com.google.gson.Gson 类检测 Google Gson 库(Google 的 JSON 库),jsonbPresent 通过 javax.json.bind.Jsonb 类检测 JSON-B 库(JavaEE标准JSON处理)。
1.1.2 类变量
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Nullable
private ApplicationContext applicationContext;
@Nullable
private ServletContext servletContext;
@Nullable
private List<Object> interceptors;
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
@Nullable
private List<HandlerMethodArgumentResolver> argumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> returnValueHandlers;
@Nullable
private List<HttpMessageConverter<?>> messageConverters;
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
}
WebMvcConfigurationSupport 类中的 applicationContext 与 servletContext 属性分别保存的是当前应用程序与 Servlet 上下文,interceptors 为当前程序注册的拦截器缓存列表,pathMatchConfigurer 属性为路径匹配配置,contentNegotiationManager 属性用于控制客户端请求类型
1.2 方法
WebMvcConfigurationSupport 类作为一个 spring 配置类,理所当然通过 Bean 注解声明了并向上下文中注入了很多必要对象,因此本文将基于使用 Bean 修饰的方法入手,即从配置对象入手对该配置类进行方法分析。
1.2.1 requestMappingHandlerMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
@SuppressWarnings("deprecation")
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
mapping.setContentNegotiationManager(contentNegotiationManager);
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;
}
}
requestMappingHandlerMapping 方法用于声明和构建 RequestMappingHandlerMapping 对象及 DispatcherServlet 类中需要的 HandlerMapping 对象一个实现,执行顺序为 0,表示首先进行执行:其首先通过 createRequestMappingHandlerMapping 方法创建基础 RequestMappingHandlerMapping 对象,并将其排序值置为 1,使用 getInterceptors 为其设置拦截器数组,将其 contentNegotiationManager 属性初始化为注入的 contentNegotiationManager 值,然后通过 getCorsConfigurations 方法获取跨域配置并保存到 CorsConfigurations 属性之中;之后根据 getPathMatchConfigurer 方法获取到的路径匹配配置项设置不同的属性值,其设置的属性值有是否进行后缀匹配 useSuffixPatternMatch(默认 false)、后缀匹配模式是否只用于扩展路径的 useRegisteredSuffixPatternMatch (默认 false)、是否默认是否可默认匹配后缀反斜杠 useTrailingSlashMatch(默认 true,示例:/users 与 /users/ 都可匹配)、URL 匹配辅助器 urlPathHelper、路径匹配器 pathMatcher 及前缀断言映射 pathPrefixes;在设置完上述属性后返回复制完成的 RequestMappingHandlerMapping 对象。
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
}
WebMvcConfigurationSupport 声明的 createRequestMappingHandlerMapping 方法直接创建空 RequestMappingHandlerMapping 对象并返回;
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
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();
}
protected void addInterceptors(InterceptorRegistry registry) {
}
}
WebMvcConfigurationSupport 声明的 getInterceptors 方法首先会通过 interceptors 属性值判断是否已经加载过拦截器,尚未加载则会使用 mvcConversionService 与 mvcResourceUrlProvider 参数创建 ConversionServiceExposingInterceptor 对象与 ResourceUrlProviderExposingInterceptor 对象,并使用新建的 InterceptorRegistry 注册器对象将上述两对象及子类通过 addInterceptors 方法注册的拦截器转换一下然后赋值到 interceptors 属性之中并在最后返回 interceptors 属性值;
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
protected void addCorsMappings(CorsRegistry registry) {
}
}
getCorsConfigurations 方法用于获取跨域配置,其和 getInterceptors 方法一样也是可以通过子类实现 addCorsMappings 方法进行扩展,但在 WebMvcConfigurationSupport 类中不提供默认值;
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected PathMatchConfigurer getPathMatchConfigurer() {
if (this.pathMatchConfigurer == null) {
this.pathMatchConfigurer = new PathMatchConfigurer();
configurePathMatch(this.pathMatchConfigurer);
}
return this.pathMatchConfigurer;
}
protected void configurePathMatch(PathMatchConfigurer configurer) {
}
}
getPathMatchConfigurer 方法与 getInterceptors 方法一样也是可以通过子类实现 configurePathMatch 方法进行扩展,其在 WebMvcConfigurationSupport 类中也不提供默认值;
1.2.2 mvcPathMatcher 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public PathMatcher mvcPathMatcher() {
PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
return (pathMatcher != null ? pathMatcher : new AntPathMatcher());
}
}
mvcPathMatcher 方法首先尝试从 pathMatchConfigurer 属性中获取 pathMatcher 对象来注入,否则直接新建 AntPathMatcher 对象进行注入;
1.2.3 mvcUrlPathHelper 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public UrlPathHelper mvcUrlPathHelper() {
UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
return (pathHelper != null ? pathHelper : new UrlPathHelper());
}
}
mvcUrlPathHelper 方法首先也会尝试从 pathMatchConfigurer 属性中获取 mvcUrlPathHelper 对象注入,否则注入新建的 UrlPathHelper 对象;
1.2.4 mvcContentNegotiationManager 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
if (this.contentNegotiationManager == null) {
ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
configurer.mediaTypes(getDefaultMediaTypes());
configureContentNegotiation(configurer);
this.contentNegotiationManager = configurer.buildContentNegotiationManager();
}
return this.contentNegotiationManager;
}
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
}
mvcContentNegotiationManager 方法在 contentNegotiationManager 属性不为空时直接返回,否则首先会使用 servlet 上下文创建 ContentNegotiationConfigurer 配置,同时将配置的媒体类型设置 getDefaultMediaTypes 方法值并使用 configureContentNegotiation 将配置交由子类扩展,最后调用 ContentNegotiationConfigurer 配置对象的 buildContentNegotiationManager 方法建造 ContentNegotiationManager 对象并保存到 contentNegotiationManager 属性之后然后返回;
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected Map<String, MediaType> getDefaultMediaTypes() {
Map<String, MediaType> map = new HashMap<>(4);
if (romePresent) {
map.put("atom", MediaType.APPLICATION_ATOM_XML);
map.put("rss", MediaType.APPLICATION_RSS_XML);
}
if (jaxb2Present || jackson2XmlPresent) {
map.put("xml", MediaType.APPLICATION_XML);
}
if (jackson2Present || gsonPresent || jsonbPresent) {
map.put("json", MediaType.APPLICATION_JSON);
}
if (jackson2SmilePresent) {
map.put("smile", MediaType.valueOf("application/x-jackson-smile"));
}
if (jackson2CborPresent) {
map.put("cbor", MediaType.APPLICATION_CBOR);
}
return map;
}
}
getDefaultMediaTypes 方法根据常量值(即是否引入对应的序列化/反序列化包)来配置对应的媒体支持;romePresent 常量为 true 即引入了 ROME 库后支持 APPLICATION_ATOM_XML 与 APPLICATION_RSS_XML,jaxb2Present 或 jackson2XmlPresent 常量为 true 即引入了 JAXB 或 Jackson XML 库后支持 APPLICATION_XML,jackson2Present、gsonPresent 或 jsonbPresent 常量为 true 即引入了 Jackson JSON、Google Gson 或 JSON-B 库后支持 APPLICATION_JSON ,jackson2SmilePresent 常量为 true 即引入了 Jackson Smile 库后支持 application/x-jackson-smile,jackson2CborPresent 常量为 true 即引入了 Jackson CBOR 库后支持 APPLICATION_CBOR。
1.2.5 viewControllerHandlerMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
protected void addViewControllers(ViewControllerRegistry registry) {
}
}
viewControllerHandlerMapping 方法首先使用 applicationContext 上下文创建 ViewControllerRegistry 注册器,随后使用 addViewControllers 方法对其进行扩展同时调用其 buildHandlerMapping 方法建造 AbstractHandlerMapping 对象,若未成功创建直接返回 null;随后依次为建造的 AbstractHandlerMapping 对象依次设置 pathMatcher、urlPathHelper、Interceptor 拦截器列表及 corsConfigurations 跨域配置。
1.2.6 BeanNameUrlHandlerMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
}
beanNameHandlerMapping 方法创建的 BeanNameUrlHandlerMapping 对象执行顺序为 2,其直接新建 BeanNameUrlHandlerMapping 对象并为其设置 nterceptor 拦截器列表及 corsConfigurations 跨配置并返回。
1.2.7 routerFunctionMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
}
routerFunctionMapping 方法创建的 RouterFunctionMapping 对象执行顺序为 3,直接新建 RouterFunctionMapping 对象并为其设置 nterceptor 拦截器列表、corsConfigurations 跨配置及 HttpMessageConverter 消息转换器列表并返回。
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
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;
}
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
}
getMessageConverters 方法在当前 messageConverters 属性不为空时直接返回,否则首先通过 configureMessageConverters 方法在子类中配置消息转换器,若未从子类获取到,则会调用 addDefaultHttpMessageConverters 方法设置默认消息转化器,最后在配置完后通过 extendMessageConverters 方法提供子类对消息转化器的扩展功能。
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
}
addDefaultHttpMessageConverters 方法首先将 ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter、ResourceRegionHttpMessageConverter、SourceHttpMessageConverter 及 AllEncompassingFormHttpMessageConverter 保存到 messageConverters 参数之中,随后也会根据常量值即通过判断支持不同的序列化方式,来注入对应的消息转换器。
1.2.8 resourceHandlerMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
}
}
resourceHandlerMapping 方法首先创建 ResourceHandlerRegistry 对象同时调用 addResourceHandlers 方法在子类上对其进行补充,随后尝试从其中获取 AbstractHandlerMapping 对象;若不为空则依次设置 pathMatcher、urlPathHelper、Interceptor 拦截器列表及 corsConfigurations 跨域配置。
1.2.9 defaultServletHandlerMapping 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
@Nullable
public HandlerMapping defaultServletHandlerMapping() {
Assert.state(this.servletContext != null, "No ServletContext set");
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
configureDefaultServletHandling(configurer);
return configurer.buildHandlerMapping();
}
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
}
defaultServletHandlerMapping 方法通过 DefaultServletHandlerConfigurer 对象与 configureDefaultServletHandling 方法配置默认 Servlet 处理器并返回。
1.2.10 requestMappingHandlerAdapter 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
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;
}
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
return new RequestMappingHandlerAdapter();
}
protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
if (this.argumentResolvers == null) {
this.argumentResolvers = new ArrayList<>();
addArgumentResolvers(this.argumentResolvers);
}
return this.argumentResolvers;
}
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
if (this.returnValueHandlers == null) {
this.returnValueHandlers = new ArrayList<>();
addReturnValueHandlers(this.returnValueHandlers);
}
return this.returnValueHandlers;
}
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
}
requestMappingHandlerAdapter 方法首先通过 createRequestMappingHandlerAdapter 方法创建 RequestMappingHandlerAdapter 对象,并依次设置 contentNegotiationManager、messageConverters、webBindingInitializer、customArgumentResolvers 以及 customReturnValueHandlers 属性值,同时在引入了 Jackson JSON 核心库是分别将 requestBodyAdvice 与 responseBodyAdvice 属性设置为 JsonViewRequestBodyAdvice 与 JsonViewResponseBodyAdvice 对象,接下来根据 configureAsyncSupport 方法配置结果进行异步配置然后返回;
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
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;
}
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
getConfigurableWebBindingInitializer 方法创建了 ConfigurableWebBindingInitializer 对象并依次设置 FormattingConversionService、Validator 与 MessageCodesResolver 属性并返回;
1.2.11 handlerFunctionAdapter 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
return new HandlerFunctionAdapter();
}
}
handlerFunctionAdapter 方法直接注入新建的 HandlerFunctionAdapter 的对象。
1.2.12 mvcConversionService 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
protected void addFormatters(FormatterRegistry registry) {
}
}
mvcConversionService 方法新建 DefaultFormattingConversionService 对象并 addFormatters 方法用于子类扩展并返回。
1.2.13 mvcValidator 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
@Nullable
protected Validator getValidator() {
return null;
}
}
mvcValidator 方法首先尝试从 getValidator 中获取自定义 Validator 验证器,未获取到时则会判断是否引入了 javax.validation.Validator 对象,若引入了直接创建 org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean 类并返回,否则创建 NoOpValidator 对象并返回。
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
private static final class NoOpValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(@Nullable Object target, Errors errors) {
}
}
}
NoOpValidator 为 Validator 接口的空实现,supports 方法直接返回 false,同时 validate 方法只有一个空实现
1.2.14 mvcUriComponentsContributor 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public CompositeUriComponentsContributor mvcUriComponentsContributor(
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("requestMappingHandlerAdapter") RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
return new CompositeUriComponentsContributor(
requestMappingHandlerAdapter.getArgumentResolvers(), conversionService);
}
}
mvcUriComponentsContributor 方法直接创建 CompositeUriComponentsContributor 对象然后返回。
1.2.15 httpRequestHandlerAdapter 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
}
HttpRequestHandlerAdapter 方法直接创建 HttpRequestHandlerAdapter 对象然后返回。
1.2.16 simpleControllerHandlerAdapter 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
}
simpleControllerHandlerAdapter 方法直接创建 SimpleControllerHandlerAdapter 对象然后返回。
1.2.17 handlerExceptionResolver 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public HandlerExceptionResolver handlerExceptionResolver(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
}
handlerExceptionResolver 方法直接首先尝试从 configureHandlerExceptionResolvers 方法从子类中获取自定义异常解析器,若未配置则使用 addDefaultHandlerExceptionResolvers 方法设置默认异常解析器列表,随后使用 HandlerExceptionResolverComposite 对其进行封装并将其执行顺序设置为 0 ,然后返回。
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,
ContentNegotiationManager mvcContentNegotiationManager) {
ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
exceptionHandlerResolver.setMessageConverters(getMessageConverters());
exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
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());
}
protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
return new ExceptionHandlerExceptionResolver();
}
}
addDefaultHandlerExceptionResolvers 调用 createExceptionHandlerExceptionResolver 创建 ExceptionHandlerExceptionResolver 对象作为基处理器,然后设置 mvcContentNegotiationManager、MessageConverter 列表、ArgumentResolver 处理器列表及 ReturnValueHandler 列表;随后若引入了 jackson JSON,会将其 ResponseBodyAdvice 设置为 JsonViewResponseBodyAdvice 对象;最后调用其 afterPropertiesSet 方法进行后处理并在处理完成后将其保存到 exceptionResolvers 变量之中,随后依次向该变量中添加 ResponseStatusExceptionResolver 与 DefaultHandlerExceptionResolver 对象然后返回;
1.2.18 handlerExceptionResolver 方法
java
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@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;
}
protected void configureViewResolvers(ViewResolverRegistry registry) {
}
}
mvcViewResolver 方法首先使用 contentNegotiationManager 与 applicationContext 值创建 ViewResolverRegistry 对象并调用 configureViewResolvers 方法对其进行配置;之后若未配置任何 viewResolver 解析器、当前上下文不为空且上下文中只拥有一个 ViewResolver 对象时则会向该注册器中添加一个 InternalResourceViewResolver 对象;最后创建 ViewResolverComposite 对象并依次设置执行顺序、ViewResolver 解析器列表、程序上下文及 servlet 上下文然后返回。
2. DelegatingWebMvcConfiguration 类
DelegatingWebMvcConfiguration 类提供了对 spring-mvc 配置的自定义扩展;
2.1 变量
java
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 类只有一个用于保存所有自定义 WebMvcConfigurer 配置对象的 WebMvcConfigurerComposite 类型 configurers 属性,setConfigurers 方法直接将上下文中的所有 WebMvcConfigurer 对象保存到 configurers 属性之中;
2.2 方法
java
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
this.configurers.configurePathMatch(configurer);
}
...
}
DelegatingWebMvcConfiguration 所有方法都是用于对 Web-mvc 自定义配置,其都是通过调用 configurers 属性的对应方法实现的;
2.3 WebMvcConfigurer 接口
java
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
...
@Nullable
default Validator getValidator() {
return null;
}
...
}
WebMvcConfigurer 的所有接口都拥有默认实现,其中没有返回值的方法直接默认空实现,拥有返回值的方法默认返回 null;
2.4 WebMvcConfigurerComposite 类
java
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
}
WebMvcConfigurerComposite 类只有一个用于保存第一次通过 addWebMvcConfigurers 方法注入的 WebMvcConfigurer 对象列表的 delegates 属性;
java
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configurePathMatch(configurer);
}
}
...
@Override
public Validator getValidator() {
Validator selected = null;
for (WebMvcConfigurer configurer : this.delegates) {
Validator validator = configurer.getValidator();
if (validator != null) {
if (selected != null) {
throw new IllegalStateException("No unique Validator found: {" +
selected + ", " + validator + "}");
}
selected = validator;
}
}
return selected;
}
...
}
WebMvcConfigurerComposite 的方法实现也是分成两种,一种是没返回值的,依次执行 delegates 属性中的对应方法,拥有返回值的则会验证 delegates 中只有一个元素或更少实现了该方法,存在多个实现了由返回值方法的对象时直接抛出异常;