SpringMVC-初始化工作
前言 上一篇主要讲了tomcat启动SpringMVC的父子容器,以及一些配置项目的初始化工作,这一篇讲解下Spring的初始化工作
一般启动SpringMVC需要使用@EnableWebMvc来开启SpringMVC
1 2 3 4 5 @Configuration @EnableWebMvc public class MyConfiguration { }
EnableWebMvc
SpringMVC的入口,开启SpringMVC的注解
1 2 3 4 5 6 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc {}
看到这种注解,依据我们Spring的经验肯定看导入的DelegatingWebMvcConfiguration的类
DelegatingWebMvcConfiguration 概述 DelegatingWebMvcConfiguration
是对Spring MVC
进行配置的一个代理类。它结合缺省配置和用户配置定义Spring MVC
运行时最终使用的配置。
DelegatingWebMvcConfiguration
继承自WebMvcConfigurationSupport
。而WebMvcConfigurationSupport
为Spring MVC
提供缺省配置。这就是上面所提到的缺省配置。
DelegatingWebMvcConfiguration又会被注入一组WebMvcConfigurer,顾名思义,这是一组”Spring MVC配置器”。这组配置器由开发人员或者框架某一部分提供,是接口WebMvcConfigurer的实现类,按照Spring的建议,通常也是一个配置类,也就是使用了注解@Configuration的类。这组WebMvcConfigurer就是上面提到的用户配置。
DelegatingWebMvcConfiguration本身使用了注解@Configuration,所以它是一个配置类,因此它也会被作为一个单例bean注册到容器和被容器注入相应的依赖。WebMvcConfigurer注入到DelegatingWebMvcConfiguration正是因为他是一个bean并且在方法void setConfigurers(List<WebMvcConfigurer> configurers)使用了注解@Autowired(required = false)。
WebMvcConfigurationSupport提供缺省配置的主要方式是定义一组bean供Spring MVC在运行时使用,而这些bean定义方法所用的配置原料供应方法给子类保留了可覆盖的回调方法用于定制化(这些定制化回调方法正好通过接口WebMvcConfigurer抽象建模)。WebMvcConfigurationSupport为这些用于定制的回调方法提供了缺省实现(比如空方法),而DelegatingWebMvcConfiguration则覆盖了这些方法,使用所注入的WebMvcConfigurers对相应的配置原料进行定制从而起到定制整个Spring MVC配置的作用。
注解@EnableWebMvc的作用其实就是引入一个DelegatingWebMvcConfiguration用于配置Spring MVC。而通常,我们正式使用注解@EnableWebMvc在某个实现了WebMvcConfigurer的配置类上来配置Spring MVC的,如下所示 :
1 2 3 4 5 @Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { }
继承关系
源代码解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 @Configuration(proxyBeanMethods = false) public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { /** * WebMvcConfigurerComposite 其实就是对多个 WebMvcConfigurer 的一个组合, * 从命名就可以看出这一点 * WebMvcConfigurerComposite 自身也实现了接口 WebMvcConfigurer, * 问 : 为什么要组合多个 WebMvcConfigurer 然后自己又实现该接口 ? * 答 : 这么做的主要目的是在配置时简化逻辑。调用者对 WebMvcConfigurerComposite * 可以当作一个 WebMvcConfigurer 来使用,而对它的每个方法的调用都又会传导到 * 它所包含的各个 WebMvcConfigurer 。 */ private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); /** * 注入一组WebMvcConfigurer,这些WebMvcConfigurer由开发人员提供,或者框架其他部分提供,已经 * 以bean的方式注入到容器中 * * @param configurers */ @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { //添加MVC配置类 this.configurers.addWebMvcConfigurers(configurers); } } /** * 以下各个方法都是对WebMvcConfigurationSupport提供的配置原材料定制回调方法的覆盖实现, * 对这些方法的调用最终都转化成了对configurers的方法调用,从而实现了定制化缺省Spring MVC * 配置的作用 * @param configurer */ @Override protected void configurePathMatch(PathMatchConfigurer configurer) { this.configurers.configurePathMatch(configurer); } @Override protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) { this.configurers.configureContentNegotiation(configurer); } @Override protected void configureAsyncSupport(AsyncSupportConfigurer configurer) { this.configurers.configureAsyncSupport(configurer); } @Override protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { this.configurers.configureDefaultServletHandling(configurer); } @Override protected void addFormatters(FormatterRegistry registry) { this.configurers.addFormatters(registry); } @Override protected void addInterceptors(InterceptorRegistry registry) { this.configurers.addInterceptors(registry); } @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { this.configurers.addResourceHandlers(registry); } @Override protected void addCorsMappings(CorsRegistry registry) { this.configurers.addCorsMappings(registry); } @Override protected void addViewControllers(ViewControllerRegistry registry) { this.configurers.addViewControllers(registry); } @Override protected void configureViewResolvers(ViewResolverRegistry registry) { this.configurers.configureViewResolvers(registry); } @Override protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { this.configurers.addArgumentResolvers(argumentResolvers); } @Override protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { this.configurers.addReturnValueHandlers(returnValueHandlers); } @Override protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { this.configurers.configureMessageConverters(converters); } @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { this.configurers.extendMessageConverters(converters); } @Override protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { this.configurers.configureHandlerExceptionResolvers(exceptionResolvers); } @Override protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { this.configurers.extendHandlerExceptionResolvers(exceptionResolvers); } @Override @Nullable protected Validator getValidator() { return this.configurers.getValidator(); } @Override @Nullable protected MessageCodesResolver getMessageCodesResolver() { return this.configurers.getMessageCodesResolver(); } }
WebMvcConfigurationSupport 概述 WebMvcConfigurationSupport是对Spring MVC进行缺省配置的工具类,同时它自身也设计了供定制缺省配置的模板方法供子类覆盖用于对缺省配置进行定制。DelegatingWebMvcConfiguration继承自WebMvcConfigurationSupport,正是利用了WebMvcConfigurationSupport的这个扩展能力从而可以实现在缺省Spring MVC配置的基础上定制出最终使用的Spring MVC配置。
WebMvcConfigurationSupport的首要功能,是检测运行环境给出一套缺省配置。最终这套配置表现为一组注册到容器的bean。其次WebMvcConfigurationSupport在定义这些bean的过程中,调用了子类可以覆盖实现的配置原料提供方法,从而提供给了子类定制化Spring MVC配置的能力。
源码解析 类静态属性定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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); }
成员属性定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @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;
注册HandlerMapping WebMvcConfigurationSupport#requestMappingHandlerMapping
创建RequestMappingHandlerMapping并完成配置交给Spring管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 @Bean 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; }
createRequestMappingHandlerMapping 1 2 3 protected RequestMappingHandlerMapping createRequestMappingHandlerMapping () { return new RequestMappingHandlerMapping (); }
RequestMappingHandlerMapping
RequestMappingHandlerMapping这个类,是负责根据注解方式来处理HandlerMethod,那就来看下它的注册过程。名词解释
Handler : 绑定了注解@RequestMapping和@Controller的类
HandlerMethod :就是Handler下某个绑定@RequestMapping注解的方法(GetMapping、PostMapping…等都绑定的有注解@RequestMapping,spring mvc在做注解解析处理生成代理对象等的时候,会做值的合并等处理,所以最终都是用RequestMapping的注解来计算,所以@Controller和@RestController的处理等同)
为什么要注册HandlerMethod
如何根据注解信息和对应方法解析绑定在一起的,如下一段代码:
1 2 3 4 5 6 7 8 9 10 @RestController @RequestMapping("/demo") public class DemoController { @RequestMapping(path = "/hello", method = RequestMethod.GET) public String hello () { return "hello, world" ; } }
spring mvc默认只有一个servlet映射/*请求,但是他可以根据请求信息:比如url:/demo/hello等匹配到hello()这个方法,这个过程是它的匹配HandlerMethod的过程,我们本文重点说的这个根据注解信息注册请求映射信息和对应的HandlerMethod的过程。
继承关系
afterPropertiesSet
AbstractHandlerMethodMapping这个类实现了接口InitializingBean(不清楚这个接口作用的同学,可以查下资料了解下),所以HandlerMethod的注册便在这个接口实现方法afterPropertiesSet()方法上了(这是因为spring 初始化bean的时候,如果某个bean实现了接口InitializingBean便会回调它的afterPropertiesSet()。
1 2 3 4 5 @Override public void afterPropertiesSet () { initHandlerMethods(); }
initHandlerMethods
扫描Beans 初始化Mapping映射关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protected void initHandlerMethods () { for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
afterPropertiesSet实现交给了initHandlerMethods,initHandlerMethods的执行流程如下:
得到所有的beanName
遍历beanNames,调用isHandler判断bean是不是一个controller,isHandler由子类实现,RequestMappingHandlerMapping的实现如下,判断bean中有没有Controller或RequestMapping
getCandidateBeanNames
获取所有Spring中的所有的Bean
1 2 3 4 5 6 protected String[] getCandidateBeanNames() { return (this .detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); }
processCandidateBean
处理候选Bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 protected void processCandidateBean (String beanName) { Class<?> beanType = null ; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'" , ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } }
isHandler
如果类上面有@Controller注解或者@RequestMapping注解
1 2 3 4 5 6 7 8 9 10 @Override protected boolean isHandler (Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
detectHandlerMethods是加载请求核心方法,执行流程如下: (1) 得到controller真实类型,controller可能被代理 (2) 根据方法上的@RequestMapping信息构建RequestMappingInfo,由RequestMappingHandlerMapping实现。从代码上可以看出,必须方法上声明@RequestMapping,类上的@RequestMapping才会生效。
detectHandlerMethods
查找controller中有@RequestMapping注解的方法,并注册到请求容器中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 protected void detectHandlerMethods (Object handler) { Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null ) { Class<?> userType = ClassUtils.getUserClass(handlerType); Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException ("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isTraceEnabled()) { logger.trace(formatMappings(userType, methods)); } methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
selectMethods
扫描目标类的所有方法判断是否有@RequestMapper注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public static <T> Map<Method, T> selectMethods (Class<?> targetType, final MetadataLookup<T> metadataLookup) { final Map<Method, T> methodMap = new LinkedHashMap <>(); Set<Class<?>> handlerTypes = new LinkedHashSet <>(); Class<?> specificHandlerType = null ; if (!Proxy.isProxyClass(targetType)) { specificHandlerType = ClassUtils.getUserClass(targetType); handlerTypes.add(specificHandlerType); } handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType)); for (Class<?> currentHandlerType : handlerTypes) { final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType); ReflectionUtils.doWithMethods(currentHandlerType, method -> { Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); T result = metadataLookup.inspect(specificMethod); if (result != null ) { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null ) { methodMap.put(specificMethod, result); } } }, ReflectionUtils.USER_DECLARED_METHODS); } return methodMap; }
调用metadataLookup.inspect(specificMethod)方法会调用到getMappingForMethod方法中,完成@RequestMapping信息构建RequestMappingInfo的工作
根据方法上的@RequestMapping信息构建RequestMappingInfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected RequestMappingInfo getMappingForMethod (Method method, Class<?> handlerType) { RequestMappingInfo info = createRequestMappingInfo(method); if (info != null ) { RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null ) { info = typeInfo.combine(info); } String prefix = getPathPrefix(handlerType); if (prefix != null ) { info = RequestMappingInfo.paths(prefix).options(this .config).build().combine(info); } } return info; }
收集方法上面的@RequestMapping以及类上面的@RequestMapping注解
将方法和类的RequestMappingInfo进行合并
封装所有的RequestMappingInfo到Map中
将RequestMappingInfo注册到请求容器中
registerHandlerMethod
注册HandlerMethod和它唯一映射信息
1 2 3 4 5 6 7 8 9 protected void registerHandlerMethod (Object handler, Method method, T mapping) { this .mappingRegistry.register(mapping, handler, method); }
register 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public void register (T mapping, Object handler, Method method) { if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) { throw new IllegalStateException ("Unsupported suspending handler method detected: " + method); } this .readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); validateMethodMapping(handlerMethod, mapping); this .mappingLookup.put(mapping, handlerMethod); List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { this .urlLookup.add(url, mapping); } String name = null ; if (getNamingStrategy() != null ) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null ) { this .corsLookup.put(handlerMethod, corsConfig); } this .registry.put(mapping, new MappingRegistration <>(mapping, handlerMethod, directUrls, name)); } finally { this .readWriteLock.writeLock().unlock(); } }
主要完成对URI以及调用方法的映射,这样RequestMapping的整个初始化工作就完成了。
注册HandlerAdapter
RequestMappingHandlerAdapter请求映射处理适配器,在SpringMVC中它是一个非常重要的类,对请求处理方法的调用主要是通过这个类来完成的(这段代码mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)。
WebMvcConfigurationSupport#requestMappingHandlerAdapter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @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; }
RequestMappingHandlerAdapter
RequestMappingHandlerAdapter实现了HandlerAdapter接口,顾名思义,表示handler的adapter,这里的handler指的是Spring处理具体请求的某个Controller的方法,也就是说HandlerAdapter指的是将当前请求适配到某个Handler的处理器。RequestMappingHandlerAdapter是HandlerAdapter的一个具体实现,主要用于将某个请求适配给@RequestMapping
类型的Handler处理。
继承关系
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public RequestMappingHandlerAdapter () { this .messageConverters = new ArrayList <>(4 ); this .messageConverters.add(new ByteArrayHttpMessageConverter ()); this .messageConverters.add(new StringHttpMessageConverter ()); try { this .messageConverters.add(new SourceHttpMessageConverter <>()); } catch (Error err) { } this .messageConverters.add(new AllEncompassingFormHttpMessageConverter ()); }
从上面的代码中我们可以看到这里默认添加了四种类型的Http数据转换器。其中我们需要关注的时候AllEncompassingFormHttpMessageConverter这个转换器,我们也去它的构造函数中看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public AllEncompassingFormHttpMessageConverter () { try { addPartConverter(new SourceHttpMessageConverter <>()); } catch (Error err) { } if (jaxb2Present && !jackson2XmlPresent) { addPartConverter(new Jaxb2RootElementHttpMessageConverter ()); } if (jackson2Present) { addPartConverter(new MappingJackson2HttpMessageConverter ()); } else if (gsonPresent) { addPartConverter(new GsonHttpMessageConverter ()); } else if (jsonbPresent) { addPartConverter(new JsonbHttpMessageConverter ()); } if (jackson2XmlPresent) { addPartConverter(new MappingJackson2XmlHttpMessageConverter ()); } if (jackson2SmilePresent) { addPartConverter(new MappingJackson2SmileHttpMessageConverter ()); } }
其实在它的父类中还添加了三种类型的Convert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public FormHttpMessageConverter () { this .supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); this .supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA); this .supportedMediaTypes.add(MediaType.MULTIPART_MIXED); this .partConverters.add(new ByteArrayHttpMessageConverter ()); this .partConverters.add(new StringHttpMessageConverter ()); this .partConverters.add(new ResourceHttpMessageConverter ()); applyDefaultCharset(); }
afterPropertiesSet
RequestMappingHandlerAdapter实现了InitializingBean,spring启动完成后就会调用afterPropertiesSet方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public void afterPropertiesSet () { initControllerAdviceCache(); if (this .argumentResolvers == null ) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this .argumentResolvers = new HandlerMethodArgumentResolverComposite ().addResolvers(resolvers); } if (this .initBinderArgumentResolvers == null ) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this .initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite ().addResolvers(resolvers); } if (this .returnValueHandlers == null ) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this .returnValueHandlers = new HandlerMethodReturnValueHandlerComposite ().addHandlers(handlers); } }
initControllerAdviceCache
在这个方法里主要是获取了带ControllerAdvice注解的类,并从这些类中查找实现了RequestBodyAdvice或者ResponseBodyAdvice接口的类,添加到requestResponseBodyAdvice集合中,另外获取所有带ModelAttribute注解且没有RequestMapping注解的方法,放到modelAttributeAdviceCache集合中,获取所有带InitBinder注解的方法放到initBinderAdviceCache的集合中。下面我们再看这一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 private void initControllerAdviceCache () { if (getApplicationContext() == null ) { return ; } List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); List<Object> requestResponseBodyAdviceBeans = new ArrayList <>(); for (ControllerAdviceBean adviceBean : adviceBeans) { Class<?> beanType = adviceBean.getBeanType(); if (beanType == null ) { throw new IllegalStateException ("Unresolvable type for ControllerAdviceBean: " + adviceBean); } Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this .modelAttributeAdviceCache.put(adviceBean, attrMethods); } Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this .initBinderAdviceCache.put(adviceBean, binderMethods); } if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); } } if (!requestResponseBodyAdviceBeans.isEmpty()) { this .requestResponseBodyAdvice.addAll(0 , requestResponseBodyAdviceBeans); } if (logger.isDebugEnabled()) { int modelSize = this .modelAttributeAdviceCache.size(); int binderSize = this .initBinderAdviceCache.size(); int reqCount = getBodyAdviceCount(RequestBodyAdvice.class); int resCount = getBodyAdviceCount(ResponseBodyAdvice.class); if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0 ) { logger.debug("ControllerAdvice beans: none" ); } else { logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize + " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice" ); } } }
getDefaultArgumentResolvers
这里我们是没有手工配置RequestMappingHandlerAdapter的,所以,会先调用getDefaultArgumentResolvers方法,获取一系列默认的HandlerMethodArgumentResolver的实现类,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers () { List<HandlerMethodArgumentResolver> resolvers = new ArrayList <>(); resolvers.add(new RequestParamMethodArgumentResolver (getBeanFactory(), false )); resolvers.add(new RequestParamMapMethodArgumentResolver ()); resolvers.add(new PathVariableMethodArgumentResolver ()); resolvers.add(new PathVariableMapMethodArgumentResolver ()); resolvers.add(new MatrixVariableMethodArgumentResolver ()); resolvers.add(new MatrixVariableMapMethodArgumentResolver ()); resolvers.add(new ServletModelAttributeMethodProcessor (false )); resolvers.add(new RequestResponseBodyMethodProcessor (getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RequestPartMethodArgumentResolver (getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RequestHeaderMethodArgumentResolver (getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver ()); resolvers.add(new ServletCookieValueMethodArgumentResolver (getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver (getBeanFactory())); resolvers.add(new SessionAttributeMethodArgumentResolver ()); resolvers.add(new RequestAttributeMethodArgumentResolver ()); resolvers.add(new ServletRequestMethodArgumentResolver ()); resolvers.add(new ServletResponseMethodArgumentResolver ()); resolvers.add(new HttpEntityMethodProcessor (getMessageConverters(), this .requestResponseBodyAdvice)); resolvers.add(new RedirectAttributesMethodArgumentResolver ()); resolvers.add(new ModelMethodProcessor ()); resolvers.add(new MapMethodProcessor ()); resolvers.add(new ErrorsMethodArgumentResolver ()); resolvers.add(new SessionStatusMethodArgumentResolver ()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver ()); if (getCustomArgumentResolvers() != null ) { resolvers.addAll(getCustomArgumentResolvers()); } resolvers.add(new RequestParamMethodArgumentResolver (getBeanFactory(), true )); resolvers.add(new ServletModelAttributeMethodProcessor (true )); return resolvers; }
SpringMVC为我们自动添加了大概26个HandlerMethodArgumentResolver的实现类。这里有一个方法需要我们注意一下:getCustomArgumentResolvers() 方法。这个方法是用来获取自定义的HandlerMethodArgumentResolver的实现类,也就是说如果我们有自己写的HandlerMethodArgumentResolver的方法的话,我们配置的属性是customArgumentResolvers,最好不要配置argumentResolvers这个属性。然后我们注意的一点是我们所添加的所以的HandlerMethodArgumentResolver的实现类,都是添加到了HandlerMethodArgumentResolverComposite这个类中,HandlerMethodArgumentResolverComposite也是HandlerMethodArgumentResolver的一个实现类。还有一点需要注意的是,这里创建了两个RequestParamMethodArgumentResolver的实例,一个传了true参数,一个传了false参数,这是用来解析不同的请求参数的。
总结 讲述了SpringMVC使用@EnableWebMvc 启动SpringMVC后首先导入DelegatingWebMvcConfiguration类,然后从父类的WebMvcConfigurationSupport通过@Bean的方式注册HandlerMapping以及HandlerAdapter,其他的还有handlerExceptionResolver异常处理器注册,mvcViewResolver视图解析器的注册等等。