1.组件概览 这里的组件指的是DispatcherServlet中直接初始化的那九个组件,不同的组件内部还会用到一些子组件。
1.1HandlerMapping 作用:根据request找到相应的处理器Handler和Interceptors。
可以实现Order接口以控制遍历HandlerMapping的顺序 ,越小越先使用优先级越高。
1 2 3 4 5 6 7 public interface HandlerMapping { default boolean usesPathPatterns () { return false ; } HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception; }
1.2HandlerAdapter 作用:调用handler来真正处理请求。
1 2 3 4 5 6 7 8 public interface HandlerAdapter { boolean supports (Object handler) ; ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; long getLastModified (HttpServletRequest request, Object handler) ; }
视图名称是handler处理器返回的,或者RequestToViewNameTranslator获取的默认视图名。
1.3HandlerExceptionResolver 作用:请求处理过程出现异常后,由此组件进行处理。只用于解析对请求做处理过程中的异常,而渲染环节产生的异常不归它管。
1 2 3 4 5 6 public interface HandlerExceptionResolver { @Nullable ModelAndView resolveException ( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) ;}
1.4ViewResolver 作用:将String类型的视图名和Locale解析为View类型的视图,找到渲染所需要的模板和所用技术(也就是视图类型)。
1 2 3 4 5 public interface ViewResolver { @Nullable View resolveViewName (String viewName, Locale locale) throws Exception; }
最常使用的UrlBasedViewResolver系列的解析器都是针对单一视图类型进行解析的,如FreeMarkerViewResolver、InternalResourceViewResolver、VelocityViewResolver、ThymeleafViewResolver。
ResourceBundleViewResolver、XmlViewResolver、BeanNameResolver可以同时解析多种类型的视图。ResourceBundleViewResolver 根据properties文件解析出视图,文件中指定视图类型和视图地址;XmlViewResolver 根据xml文件解析出视图;BeanNameResolver 是根据viewName从ApplicationContext容器中查找相应的bean做为View。
1.5RequestToViewNameTranslator 作用:处理返回的ModelAndVIew对象中即没有view也没有设置viewName的情况,这时需要从request获取viewName。即定义了如何从请求对象获取viewName。
1 2 3 4 public interface RequestToViewNameTranslator { @Nullable String getViewName (HttpServletRequest request) throws Exception; }
1.6LocaleResolver 作用:从request中解析出Locale。
1 2 3 4 5 6 public interface LocaleResolver { Locale resolveLocale (HttpServletRequest request) ; void setLocale (HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) ; }
Spring MVC中主要在两个地方用到了Locale :1.ViewResolver解析视图的时候2.使用到国际化资源或者主题的时候。
我们可以通过MVC拦截器 LocaleChangeInterceptor 来拦截请求的请求参数,从而设置改变请求的Locale属性。比如http://localhost:8080?locale=zh_cn就会将请求的Locale设置为中文。
1.7ThemeResolver 作用:根据请求解析主题名称。
1 2 3 4 5 6 public interface ThemeResolver { String resolveThemeName (HttpServletRequest request) ; void setThemeName (HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable String themeName) ; }
Spring MVC中一套主题对应一个properties文件,里面存放着跟当前主题相关的所有资源,如图片、css样式等。例如:
ThemeResolver 的作用是从request解析出主题名;ThemeSource 则是根据主题名找到具体的主题;Theme 是ThemeSource找出的一个具体的主题,可以通过它获取主题里面的资源。
获取主题资源是在RequestContext中。
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 public Theme getTheme () { if (this .theme == null ) { this .theme = RequestContextUtils.getTheme(this .request); if (this .theme == null ) { this .theme = getFallbackTheme(); } } return this .theme; } public static Theme getTheme (HttpServletRequest request) { ThemeResolver themeResolver = getThemeResolver(request); ThemeSource themeSource = getThemeSource(request); if (themeResolver != null && themeSource != null ) { String themeName = themeResolver.resolveThemeName(request); return themeSource.getTheme(themeName); } else { return null ; } }
ThemeResolver的默认实现是 FixedThemeResolver ,这里边使用固定的默认主题”theme”。
ThemeSource的默认实现是WebApplicationContext的实现类 。默认底层实现是ResourceBundleThemeSource,即WebApplicationContext封装了themesource属性的实现类型为ResourceBundleThemeSource,具体创建过程在UiApplicationContextUtils的initThemeSource方法 。
1 2 themeSource = new ResourceBundleThemeSource ();
Spring MVC中主题切换和Locale的切换使用相同的模式,也是使用Interceptor,即ThemeChangeInterceptor 。
1.8MultipartResolver 作用:用于处理上传请求,处理方法是将普通request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取到File,或多文件getFileMap。
1 2 3 4 5 6 7 8 public interface MultipartResolver { boolean isMultipart (HttpServletRequest request) ; MultipartHttpServletRequest resolveMultipart (HttpServletRequest request) throws MultipartException; void cleanupMultipart (MultipartHttpServletRequest request) ; }
1.9FlashMapManager 作用:管理FlashMap。
FlashMap主要用在redirect中传递参数。
1 2 3 4 5 6 public interface FlashMapManager { FlashMap retrieveAndUpdate (HttpServletRequest request, HttpServletResponse response) ; void saveOutputFlashMap (FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) ; }
retrieveAndUpdate 方法用于恢复参数,并将恢复过的和超时的参数从保存介质中删除;saveOutputFlashMap 用于将参数保存起来。
默认实现是 SessionFlashMapManager ,它是将参数保存到session中。
整个redirect的参数通过FlashMap的传递过程分为三步 :
1.在处理器中将需要传递的参数设置到outputFlashMap中 。当处理器处理完请求时,如果是redirect类型的返回值RequestMappingHandlerAdapter会将其设置到outputFlashMap中 。即adapter的getModelAndView方法中实现。
2.在RedirectView 的renderMergedOutputModel方法中调用FlashMapManager的saveOutputFlashMap方法 ,将outputFlashMap中的参数设置到Session中。
3.请求redirect后DispatcherServlet的doService会调用FlashMapManager的retrieveAndUpdate方法 从Session中获取inputFlashMap并设置到Request的属性中备用,同时从Session中删除。
2.HandlerMapping HandlerMapping的继承结构如图:
2.1AbstractHandlerMapping 是HandlerMapping的抽象实现,所有HandlerMapping都继承自AbstractHandlerMapping 。
AbstractHandlerMapping采用模板模式设计了HandlerMapping实现的整体结构,子类只需要通过模板方法提供一些初始值或具体的算法即可。
创建AbstractHandlerMapping之器 1.initApplicationContext方法
作用:初始化HandlerMapping的拦截器,包括其interceptors属性和adaptedInterceptors属性,具体初始化方式就是新增 拦截器到属性中。
由于AbstractHandlerMapping继承了WebAppliactionObjectSupport,所以该对象创建时会调用父类的setApplicationContext方法,然后其方法又会调用本类的initApplicationContext()方法。即AbstractHandlerMapping的初始化就是在initApplicationContext方法实现 。
1 2 3 4 5 protected void initApplicationContext () throws BeansException { extendInterceptors(this .interceptors); detectMappedInterceptors(this .adaptedInterceptors); initInterceptors(); }
2.extendInterceptors方法
作用:初始化HandlerMapping的interceptors属性
是模板方法 ,用于给子类提供一个添加(或者修改)Interceptors的入口,不过在现有Spring MVC的实现中并没有使用。
3.detectMappedInterceptors方法
作用:将Spring MVC容器及父容器中的所有MappedInterceptor类型的Bean添加到HandlerMapping的 adaptedInterceptors 属性 。即初始化HandlerMapping的adaptedInterceptors属性。
即将用户注册的按请求路径是否生效的拦截器MappedInterceptor添加到HandlerMapping的adaptedInterceptors属性中。
1 2 3 4 protected void detectMappedInterceptors (List<HandlerInterceptor> mappedInterceptors) {mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors( obtainApplicationContext(), MappedInterceptor.class, true , false ).values()); }
4.initInterceptors方法
作用:初始化HandlerMapping的adaptedInterceptors属性。将interceptors属性中的拦截器全部适配到添加到adaptedInterceptors 。
1 2 3 4 5 6 7 8 9 10 11 protected void initInterceptors() { if (!this.interceptors.isEmpty()) { for (int i = 0; i < this.interceptors.size(); i++) { Object interceptor = this.interceptors.get(i); if (interceptor == null) { throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); } this.adaptedInterceptors.add(adaptInterceptor(interceptor)); } } }
AbstractHandlerMapping之用 主要是getHandler方法 在起作用。getHandler方法就是AbstractHandlerMapping的底层设计 。
getHandler方法的实现分为两部分,getHandlerExecutionChain之前是找Handler,getHandlerExecutionChain方法用于添加拦截器。
1.getHandler方法
找Handler的过程 :
通过 getHandlerInternal(request) 方法查找 ,这是模板方法,留给子类具体实现(也是子类主要做的事情)。
如果没有从子类获取到则使用默认的Handler 。默认的Handler保存在AbstractHandlerMapping的一个Object类型的属性defaultHandler中。
如果默认Handler为null则方法返回null 。
如果找到的Handler类型是String,则从Spring MVC容器里查找相应名字的Bean 。
对应的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public final HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null ) { handler = getDefaultHandler(); } if (handler == null ) { return null ; } if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } 。。。 }
2.getHandlerExecutionChain方法
作用:创建HandlerExecutionChain对象,然后将adaptedInterceptors属性中符合要求的拦截器添加进去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected HandlerExecutionChain getHandlerExecutionChain (Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain (handler)); for (HandlerInterceptor interceptor : this .adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
2.2AbstractUrlHandlerMapping系列 AbstractUrlHandlerMapping 它是通过请求的url来进行匹配查找处理器执行链的。
原理:将url与对应的Handler保存在一个Map中 ,在getHandlerInternal方法中使用url从Map中获取Handler,AbstractUrlHandlerMapping实现了getHandlerInternal方法具体从url中获取Handler的过程,而Map的初始化则交给了子类去完成 。
AbstractUrlHandlerMapping包含的属性如下:
1 2 3 4 5 6 7 8 9 10 11 12 public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping { @Nullable private Object rootHandler; private boolean useTrailingSlashMatch = false ; private boolean lazyInitHandlers = false ; private final Map<String, Object> handlerMap = new LinkedHashMap <>(); private final Map<PathPattern, Object> pathPatternHandlerMap = new LinkedHashMap <>();
从源码来看,AbstractUrlHandlerMapping即支持直接literal字面量匹配也支持pattern模糊匹配。
PathPattern 和 AntPathMatcher 都支持url的pattern模糊匹配,但PathPattern更高效且合适 。
1.getHandlerInternal方法
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 protected Object getHandlerInternal (HttpServletRequest request) throws Exception { String lookupPath = initLookupPath(request); Object handler; if (usesPathPatterns()) { RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request); handler = lookupHandler(path, lookupPath, request); } else { handler = lookupHandler(lookupPath, request); } if (handler == null ) { Object rawHandler = null ; if (StringUtils.matchesCharacter(lookupPath, '/' )) { rawHandler = getRootHandler(); } if (rawHandler == null ) { rawHandler = getDefaultHandler(); } if (rawHandler != null ) { if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = obtainApplicationContext().getBean(handlerName); } validateHandler(rawHandler, request); handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null ); } } return handler; }
方法逻辑如下:
调用父类initLookupPath方法。从请求对象获取解析 (URL解码如:%20)后的请求路径 ,获取的请求路径不包括context path和请求参数
调用本类lookupHandler方法。从handlerMap和pathPatternHandlerMap查找处理器 。
如果从Map中未找到,则尝试使用根路径和默认的handler ,获取到后要构建成处理器执行链。
2.initLookupPath方法
作用:获取真正用于匹配的请求路径,即不包含context path、不包含请求参数、且被URL解码的路径 。
1 2 3 4 5 6 7 8 9 10 11 12 protected String initLookupPath(HttpServletRequest request) { //1.如果PathPatternParser属性在handlermapping存在,则通过ServletRequestPathUtils进行如下路径获取 if (usesPathPatterns()) { request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE); RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request); String lookupPath = requestPath.pathWithinApplication().value(); return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath); } else { //2.如果不存在,则通过UrlPathHelper进行路径获取 return getUrlPathHelper().resolveAndCacheLookupPath(request); } }
3.lookupHandler方法 (核心方法)
作用:根据指定的路径查找匹配的handler处理器执行链。
有两种模式:lookupHandler(path, lookupPath, request)和lookupHandler(lookupPath, request)
1 2 3 4 5 6 7 8 if (usesPathPatterns()) { RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request); handler = lookupHandler(path, lookupPath, request); } else { handler = lookupHandler(lookupPath, request); }
lookupHandler方法用于使用lookupPath从Map中查找Handler,不过很多时候并不能直接通过字面量从Map中get到,因为很多Handler都是用了Pattern的匹配模式,如”/show/article/*”,这时就要进行模糊匹配。
此外一个lookupHandler还可能跟多个Pattern相匹配 ,这时还要选择其中最优的 ,所以查找过程并不是直接从Map中获取。
先分析简单的模式方法lookupHandler(lookupPath, request),此方法使用PathMatcher对lookupPath和pattern进行匹配 。
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 protected Object lookupHandler (String lookupPath, HttpServletRequest request) throws Exception { Object handler = getDirectMatch(lookupPath, request); if (handler != null ) { return handler; } List<String> matchingPatterns = new ArrayList <>(); for (String registeredPattern : this .handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, lookupPath)) { matchingPatterns.add(registeredPattern); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/" ) && getPathMatcher().match(registeredPattern + "/" , lookupPath)) { matchingPatterns.add(registeredPattern + "/" ); } } } String bestMatch = null ; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(lookupPath); if (!matchingPatterns.isEmpty()) { matchingPatterns.sort(patternComparator); bestMatch = matchingPatterns.get(0 ); } if (bestMatch != null ) { handler = this .handlerMap.get(bestMatch); if (handler == null ) { if (bestMatch.endsWith("/" )) { handler = this .handlerMap.get(bestMatch.substring(0 , bestMatch.length() - 1 )); } if (handler == null ) { throw new IllegalStateException ( "Could not find handler for best pattern match [" + bestMatch + "]" ); } } if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, lookupPath); Map<String, String> uriTemplateVariables = new LinkedHashMap <>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestMatch, matchingPattern) == 0 ) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, lookupPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables); } return null ; }
buildPathExposingHandler 方法用于封装构造handler处理器执行链,用于给查找到的Handler注册两个拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor,这是两个内部拦截器,主要是将匹配的结果保存到请求对象的属性中 。
PathMatcher接口
作用:基于字符串的路径匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface PathMatcher { boolean isPattern (String path) ; boolean match (String pattern, String path) ; boolean matchStart (String pattern, String path) ; String extractPathWithinPattern (String pattern, String path) ; Map<String, String> extractUriTemplateVariables (String pattern, String path) ; Comparator<String> getPatternComparator (String path) ; String combine (String pattern1, String pattern2) ; }
其默认实现类是AntPathMatcher。
AntPathMatcher 类
ant风格的路径匹配器
//TODO源码待解析
再**分析复杂的模式方法lookupHandler(path, lookupPath, request)**,此方法使用PathPattern进行匹配。
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 protected Object lookupHandler ( RequestPath path, String lookupPath, HttpServletRequest request) throws Exception { Object handler = getDirectMatch(lookupPath, request); if (handler != null ) { return handler; } List<PathPattern> matches = null ; for (PathPattern pattern : this .pathPatternHandlerMap.keySet()) { if (pattern.matches(path.pathWithinApplication())) { matches = (matches != null ? matches : new ArrayList <>()); matches.add(pattern); } } if (matches == null ) { return null ; } if (matches.size() > 1 ) { matches.sort(PathPattern.SPECIFICITY_COMPARATOR); } PathPattern pattern = matches.get(0 ); handler = this .pathPatternHandlerMap.get(pattern); if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = pattern.extractPathWithinPattern(path.pathWithinApplication()).value(); pathWithinMapping = UrlPathHelper.defaultInstance.removeSemicolonContent(pathWithinMapping); return buildPathExposingHandler(handler, pattern.getPatternString(), pathWithinMapping, null ); }
4.registerHandler方法
作用:初始化AbstractUrlHandlerMapping的Map类型属性,承担AbstractUrlHandlerMapping的创建工作。
由子类调用 ,这样不同的子类就可以通过注册不同的Handler将组件创建出来。
registerHandler(String[] urlPaths, String beanName)方法
1 2 3 4 5 6 protected void registerHandler (String[] urlPaths, String beanName) throws BeansException, IllegalStateException { for (String urlPath : urlPaths) { registerHandler(urlPath, beanName); } }
registerHandler(String urlPath, Object handler)方法
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 protected void registerHandler (String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null" ); Assert.notNull(handler, "Handler object must not be null" ); Object resolvedHandler = handler; if (!this .lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; ApplicationContext applicationContext = obtainApplicationContext(); if (applicationContext.isSingleton(handlerName)) { resolvedHandler = applicationContext.getBean(handlerName); } } Object mappedHandler = this .handlerMap.get(urlPath); if (mappedHandler != null ) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException (); } } else { if (urlPath.equals("/" )) { setRootHandler(resolvedHandler); } else if (urlPath.equals("/*" )) { setDefaultHandler(resolvedHandler); } else { this .handlerMap.put(urlPath, resolvedHandler); if (getPatternParser() != null ) { this .pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler); } } } }
SimpleUrlHandlerMapping 是AbstractUrlHandlerMapping的直接实现子类。
通过重写父类的initApplicationContext方法在创建组件对象时 调用**registerHandlers(Map<String, Object> urlMap)**方法来完成Handler的注册,方法内部又调用了registerHandler(url, handler)父类方法。
原理 :通过registerHandlers将urlMap读取出来,然后将key带上/前缀,将value去掉空白符号,然后注册。
SimpleUrlHandlerMapping类非常简单,就是直接将配置的内容注册到了AbstractUrlHandlerMapping的属性中。
AbstractDetectingUrlHandlerMapping 是AbstractUrlHandlerMapping的子抽象类。
也是通过重写父类的initApplicationContext方法来完成Handler的注册,里面调用了detectHandlers方法。
原理 :从容器中获取所有的beanName,遍历beanName尝试解析其对应的urls,解析出来非空则执行注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected void detectHandlers () throws BeansException { ApplicationContext applicationContext = obtainApplicationContext(); String[] beanNames = (this .detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : applicationContext.getBeanNamesForType(Object.class)); for (String beanName : beanNames) { String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { registerHandler(urls, beanName); } } }
BeanNameUrlHandlerMapping实现类实现非常简单,检查beanName和alias是不是以”/“开头,如果是则将beanName和alias做为urls 。
2.3AbstractHandlerMethodMapping系列 这个系列是将Method作为Handler来使用的,这也是我们现在用的最多的一种Handler ,经常使用的@RequestMapping所注释的方法就是这种Handler,它有一个专门的类型HandlerMethod 。
它是Request和HandlerMethod的映射Map。
创建AbstractHandlerMethodMapping系列之器 泛型T 是用来代表匹配Handler的条件 专门使用的一种类,这里的条件不仅是url还可以有很多其他条件,如请求类型、请求参数、Header等。
RequestCondition
默认泛型使用的是RequestMappingInfo 。RequestMappingInfo实现了RequestCondition接口 ,此接口专门用于保存从request提取出的用于匹配Handler的条件 。
1 2 3 4 5 6 7 public interface RequestCondition <T> { T combine (T other) ; T getMatchingCondition (HttpServletRequest request) ; int compareTo (T other, HttpServletRequest request) ;
AbstractRequestCondition 中重写了equals、hashCode和toString三个方法,有8个子类,除了CompositeRequestCondition外每一个子类表示一种匹配条件。
RequestCondition的另一个实现就是这里要用的RequestMappingInfo ,它里面其实就是用七个属性保存了七个RequestCondition,在匹配时使用那七个变量进行匹配 ,这也就是可以在@RequestMapping中给处理器指定多种匹配方式的原因。
AbstractHandlerMethodMapping中的核心属性是private final MappingRegistry mappingRegistry = new MappingRegistry();即一个映射注册器对象。这个注册器维护了所有的关于HandlerMethod的映射。
MappingRegistry又封装了三个最重要的Map:
1 2 3 4 5 6 7 class MappingRegistry {private final Map<T, MappingRegistration<T>> registry = new HashMap <>();private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap <>();private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap <>();
这里的name是使用HandlerMethodMappingNamingStrategy策略的实现类从HandlerMethod中解析出来的,默认使用RequestMappingInfoHandlerMethodMappingNamingStrategy实现类,解析规则是:类名里的大写字母组合+”#”+方法名 。
正常匹配过程中无需使用这个Map。
1.afterPropertiesSet方法
作用:初始化AbstractHandlerMethodMapping的属性
AbstractHandlerMethodMapping实现了InitializingBean接口,所以spring容器会自动调用其afterPropertiesSet方法,afterProperties方法 又交给initHandlerMethods方法 完成具体的初始化。
1 2 3 public void afterPropertiesSet () { initHandlerMethods(); }
2.initHandlerMethods方法
作用:从容器中扫描所有的bean,然后根据一定的规则筛选出Handler,然后注册。默认会去除以”scopedTarget.”开头的beanName。
1 2 3 4 5 6 7 8 9 10 11 12 protected void initHandlerMethods () { for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
3.processCandidateBean方法
作用:校验指定beanName的类型是否为handler,如果是则调用detectHandlerMethods(beanName)方法进行注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected void processCandidateBean (String beanName) { Class<?> beanType = null ; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } }
isHandler方法由子类实现 ,即如何筛选容器中的bean由子类实现。
4.detectHandlerMethods方法(核心方法 )
作用:注册。
通过一系列反射操作,先获取handler的真实类型,再从真实类型中遍历其方法反射对象,并通过getMappingForMethod(method, userType)方法获取请求条件对象,并构造出methods映射集合,最后遍历methods来调用registerHandlerMethod(handler, invocableMethod, mapping)进行注册到map中。
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 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 (); } }); methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
方法分为两步:
首先从传入的处理器中找到符合要求的方法,根据getMappingForMethod方法来找。
然后使用registerHandlerMethod进行注册(也就是保存到Map中)。
5.RequestMappingHandlerMapping的getMappingForMethods方法
作用:通过类上和方法上@RequestMapping注解来创建RequestMappingInfo对象 ,并把它们合并返回。
它是根据@RequstMapping注解来找匹配条件的,如果没有则返回null,如果有则根据注解的内容来创建RequestMappingInfo类型的匹配条件对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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; }
6.RequestMappingHandlerMapping的createRequestMappingInfo方法
作用:通过 方法Mthod反射对象或者所属类Class对象上的注解对象来创建RequestMappingInfo
1 2 3 4 5 6 7 8 9 private RequestMappingInfo createRequestMappingInfo (AnnotatedElement element) { RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null ); }
7.registerHandlerMethod方法
作用:注册HandlerMethod相关映射到mappingRegistry属性中。
1 2 3 4 protected void registerHandlerMethod (Object handler, Method method, T mapping) { this .mappingRegistry.register(mapping, handler, method); }
8.MappingRegistry类的register方法
作用:将请求条件对象、handler的名字、Mthod反射对象转化一下注册到规范的三个Map中。
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 public void register (T mapping, Object handler, Method method) { this .readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); validateMethodMapping(handlerMethod, mapping); Set<String> directPaths = AbstractHandlerMethodMapping.this .getDirectPaths(mapping); for (String path : directPaths) { this .pathLookup.add(path, mapping); } String name = null ; if (getNamingStrategy() != null ) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null ) { corsConfig.validateAllowCredentials(); this .corsLookup.put(handlerMethod, corsConfig); } this .registry.put(mapping, new MappingRegistration <>(mapping, handlerMethod, directPaths, name, corsConfig != null )); } finally { this .readWriteLock.writeLock().unlock(); } }
首先检查一下registry 这个Map里是不是已经有这个匹配条件了,如果有而且所对应的值和现在传入的HandlerMethod不是同一个则抛出异常;否则依次添加到三个Map里 。
AbstractHandlerMethodMapping系列之用 1.getHandlerInternal方法
作用:根据请求对象获取HandlerMethod对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected HandlerMethod getHandlerInternal (HttpServletRequest request) throws Exception { String lookupPath = initLookupPath(request); this .mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null ); } finally { this .mappingRegistry.releaseReadLock(); } }
2.lookupHandlerMethod方法
作用:通过lookupPath和请求对象,从mappingRegistry查找对应最匹配的的HandlerMethod返回。
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 protected HandlerMethod lookupHandlerMethod (String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList <>(); List<T> directPathMatches = this .mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null ) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { addMatchingMappings(this .mappingRegistry.getRegistrations().keySet(), matches, request); } if (!matches.isEmpty()) { Match bestMatch = matches.get(0 ); if (matches.size() > 1 ) { Comparator<Match> comparator = new MatchComparator (getMappingComparator(request)); matches.sort(comparator); bestMatch = matches.get(0 ); if (CorsUtils.isPreFlightRequest(request)) { for (Match match : matches) { if (match.hasCorsConfig()) { return PREFLIGHT_AMBIGUOUS_MATCH; } } } else { Match secondBestMatch = matches.get(1 ); if (comparator.compare(bestMatch, secondBestMatch) == 0 ) { Method m1 = bestMatch.getHandlerMethod().getMethod(); Method m2 = secondBestMatch.getHandlerMethod().getMethod(); String uri = request.getRequestURI(); throw new IllegalStateException ( "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}" ); } } } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod()); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.getHandlerMethod(); } else { return handleNoMatch(this .mappingRegistry.getRegistrations().keySet(), lookupPath, request); } }
2.4小结 HandlerMapping的整体结构在AbstractHandlerMapping中设计,简单来说其功能就是根据request找到Handler和Interceptors,组合成HandlerExecutionChain类型并返回 。找到Handler的过程通过模板方法getHandlerInternal留给子类实现,查找Interceptors则是AbstractHandlerMapping自己完成的 。
//TODO RequestMappingHandlerMapping.java源码待解析
3.HandlerAdapter HandlerAdapter是具体使用Handler来干活的,每个HandlerAdapter封装了一种Handler的具体使用方法 。
RequestMappingHandlerAdapter的实现非常复杂,而其它的非常简单,因为其它三个Handler的格式都是固定的,只需要调用固定的方法即可,但是RequestMappingHandlerAdapter所处理的Handler可以是任意的方法 ,没有任何约束,这就极大地增加了难度。
3.1RequestMappingHandlerAdapter概述 AbstractHandlerMethodAdapter非常简单,三个接口方法分别调用了自定义的模板方法supportsInternal、handleInternal、getLastModifiedInternal。即它只支持handler类型为HandlerMethod类型 。
RequestMappingHandlerAdapter是Spring MVC最复杂的组件!!!
核心方法就是handleInternal方法 。这个方法是实际使用Handler处理请求的方法。具体过程大致分为三步:
准备 好处理器所需要的参数 。
使用处理器处理请求 。
处理返回值 ,也就是将不同类型的返回值统一处理成ModelAndView类型。
这三步里面第2步是最简单的,直接使用反射技术调用处理器执行就可以了,第三步也还算简单,最麻烦的是第一步 。
这第一步根据处理器的需要设置参数,而参数类型、个数都是不确定的,所以难度非常大。
参数具体解析是使用HandlerMethodArgumentResolver 类型的组件完成的,不同类型的参数使用不同的ArgumentResolver来解析。
@InitBinder注解
只用于注解在方法上,有@InitBinder注解的方法用于初始化WebDataBinder,我们可以在其中做一些WebDataBinder初始化的工作 ,如注册校验器、注册自己的参数编辑器 等。
可以在Controller中通过以下代码注册一个转换Date类型的编辑器 ,这样就可以将”yyyy-MM-dd”类型的String转换成Date类型。
@ModelAttribute注解
@ModelAttribute注解如果用在方法上,则用于设置参数 ,它会在执行处理(执行HandlerMethod前)前将参数设置到Model中。
@ModelAttribute注解如果用在参数上,则表示需要使用 指定的ArgumentResolver来解析参数。
如果想让以上两个注解在所有处理器中都起作用 ,我们可以定义一个类,然后在类上加@ControllerAdvice注解,并将@InitBinder、@ModelAttribute注释的方法放进去就可以了,这样每个Handler调用前都会调用这些方法。
3.2RequestMappingHandlerAdapter自身结构 RequestMappingHandlerAdapter自身的结构并不复杂,不过其中使用了很多组件。所以要准确理解各个组件的作用。
创建RequestMappingHandlerAdapter之器 RequestMappingHandlerAdapter的创建在afterPropertiesSet方法 中实现。
1.afterPropertiesSet方法
作用:初始化 RequestMappingHandlerAdapter 的6个属性组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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); } }
介绍一下这六个属性:
argumentResolvers:用于给处理器方法 和注解了@ModelAttribute的方法 设置参数。
initBinderArgumentResolvers:用于给注解了@InitBinder的方法设置参数。
returnValueHandlers:用于将处理器的返回值处理成ModelAndVieW的类型。
modelAttributeAdviceCache和initBinderAdviceCache:分别用于缓存@ControllerAdvice注解里面注释了@ModelAttribute和@InitBinder的方法,也就是全局的@ModelAttribute和@InitBinder的方法 。而每个处理器自己的@ModelAttribute和@InitBinder的方法是在第一次使用处理器处理请求时缓存起来的。
requestResponseBodyAdvice:用来保存实现了RequestBodyAdvice或者ResponseBodyAdvice接口的类。
这些属性都是复数形式,也就是可以有多个,在使用的时候是按顺序调用的,所以这些属性初始化时的添加顺序就非常重要了。
2.initControllerAdviceCache方法
作用:从容器中 获取bean来初始化modelAttributeAdviceCache、initBinderAdviceCache和requestResponseBodyAdvice属性
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 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); } }
3.getDefualtXXX方法
作用:通过new 直接创建组件初始化argumentResolvers、initBinderArgumentResolvers、returnValueHandlers属性。
参数解析器分为四类:通过注解解析的解析器、通过类型解析的解析器、自定义的解析器和可以解析所有类型的解析器。
通过定义内置的参数解析器,也相当于定义了方法参数的来源 。
RequestMappingHandlerAdapter之用 RequestMappingHandlerAdapter处理请求的入口方法是handleInternal 。
1.handleInternal方法 作用:校验请求、执行请求、添加Cache-Control响应头
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 protected ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); if (this .synchronizeOnSession) { HttpSession session = request.getSession(false ); if (session != null ) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this .cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }
这里真正起作用的代码只有两句,也是两个方法:checkRequest和invokeHandlerMethod 方法。这个方法通过synchronizeOnSession属性设置是否通过同步session来执行方法。
如果handlerMethod方法参数中带有注解@SessionAttributes,就会执行applyCacheSeconds(response,0(默认的))方法,如果没有就会执行prepareResponse(response) -> applyCacheSeconds(response,-1(默认的))方法。
applyCacheSeconds会调用applyCacheControl,并根据second不同设置不同的Cache-Control响应头,以控制浏览器对响应的缓存策略。
RequestMappingHandlerAdapter的cacheSecondsForSessionAttributeHandlers和cacheSeconds属性其实与服务端的Session超时并没有关系 ,而是用于设置客户端浏览器 response缓存 相关的Header参数。
@SessionAttributes注解
2.invokeHandleMethod方法 这个方法非常重要,它具体执行请求的处理。
invokeHandlerMethod方法首先 使用request和response创建了ServletWebRequest类,在ArgumentResolver解析参数时使用的request就是这个webRequest 。
接着对WebDataBinderFactory、ModelFactory、ServletInvocableHandlerMethod这三个类型的变量进行了定义和初始化。
WebDataBinderFactory
作用:是用来创建 WebDataBinder 的,WebDataBinder用于参数绑定,主要功能就是实现参数跟String之间的类型转换。ArgumentResolver在进行参数解析的过程中会用到WebDataBinder ,另外ModelFactory在更新Model时也会用到它。
WebDataBinder
继承自DataBinder类,有三个直接实现类。
先来看一下DataBinder。它实现了两个接口TypeConverter、PropertyEditorRegistry,即DataBinder和WebDataBinder是一个类型转换器和属性编辑注册器。通过属性编辑注册器接口来注册属性编辑器到DataBinder,再通过属性编辑器实现类型转换器 (java内置提供了一些属性编辑器来实现string=>目标类型的转换)。
即DataBinder核心是类型转换器,而类型转换器的核心是属性编辑器。类型转换器提供了方便的高层封装方法。
类型转换器接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface TypeConverter { <T> T convertIfNecessary (@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException; <T> T convertIfNecessary (@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException; <T> T convertIfNecessary (@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException; default <T> T convertIfNecessary (@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException { throw new UnsupportedOperationException ("TypeDescriptor resolution not supported" ); }
属性编辑器注册器接口
1 2 3 4 5 6 7 8 9 public interface PropertyEditorRegistry { void registerCustomEditor (Class<?> requiredType, PropertyEditor propertyEditor) ; void registerCustomEditor (@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor) ; PropertyEditor findCustomEditor (@Nullable Class<?> requiredType, @Nullable String propertyPath) ;
DataBinder的作用如下:Binder that allows for setting property values on a target object, including support for validation and binding result analysis.可以设置对象属性,并进行校验和绑定结果分析 。
WebDataBinderFactory的创建过程就是将符合条件的注释了@InitBinder的方法找出来,并使用它们创建出ServletRequestDataBinderFactory类型的WebDataBinderFactory。
1.getDataBinderFactory方法
作用:使用HandlerMethod创建WebDataBinderFactory
WebDataBinderFactory的创建过程就是将符合条件的注释了@InitBinder的方法找出来 ,并使用它们创建出ServletRequestDataBinderFactory 类型的WebDataBinderFactory
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 private WebDataBinderFactory getDataBinderFactory (HandlerMethod handlerMethod) throws Exception { Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = this .initBinderCache.get(handlerType); if (methods == null ) { methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); this .initBinderCache.put(handlerType, methods); } List<InvocableHandlerMethod> initBinderMethods = new ArrayList <>(); this .initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); for (Method method : methodSet) { initBinderMethods.add(createInitBinderMethod(bean, method)); } } }); for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(createInitBinderMethod(bean, method)); } return createDataBinderFactory(initBinderMethods); } private InvocableHandlerMethod createInitBinderMethod (Object bean, Method method) { InvocableHandlerMethod binderMethod = new InvocableHandlerMethod (bean, method); if (this .initBinderArgumentResolvers != null ) { binderMethod.setHandlerMethodArgumentResolvers(this .initBinderArgumentResolvers); } binderMethod.setDataBinderFactory(new DefaultDataBinderFactory (this .webBindingInitializer)); binderMethod.setParameterNameDiscoverer(this .parameterNameDiscoverer); return binderMethod; } protected InitBinderDataBinderFactory createDataBinderFactory (List<InvocableHandlerMethod> binderMethods) throws Exception { return new ServletRequestDataBinderFactory (binderMethods, getWebBindingInitializer()); }
ModelFactory
ModelFactory 是用来处理Model的,主要包含两个功能:1.在处理器具体处理之前对Model进行初始化 ,2.在处理完请求后对Model参数进行更新 。
对Model初始化具体包括三部分内容:1.将原来的SessionAttributes中的值设置到Model;2.执行相应注释了@ModelAttribute的方法并将其设置到Model;3.处理器中注释了@ModelAttribute的参数如果同时在SessionAttributes也配置了,而且在mavContainer中还没有值则从全部SessionAttributes(可能是其它处理器设置的值)中查找出并设置进去。
2.getModelFactory方法
作用:使用HandlerMethod和WebDataBinderFactory创建ModelFactory
ModelFactory的创建过程就是将注释了@ModelAttribute却没有注释@RequestMapping的方法找出来 ,并使用它们创建出ModelFactory对象 。
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 private ModelFactory getModelFactory (HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod); Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = this .modelAttributeCache.get(handlerType); if (methods == null ) { methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); this .modelAttributeCache.put(handlerType, methods); } List<InvocableHandlerMethod> attrMethods = new ArrayList <>(); this .modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); for (Method method : methodSet) { attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } } }); for (Method method : methods) { Object bean = handlerMethod.getBean(); attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } return new ModelFactory (attrMethods, binderFactory, sessionAttrHandler); } private SessionAttributesHandler getSessionAttributesHandler (HandlerMethod handlerMethod) { return this .sessionAttributesHandlerCache.computeIfAbsent( handlerMethod.getBeanType(), type -> new SessionAttributesHandler (type, this .sessionAttributeStore)); }
ServletInvocableHandlerMethod
非常重要 ,它继承自HandlerMethod,并且可以直接执行。实际请求的处理就是通过它来执行的,参数绑定、处理请求以及返回值处理都在它里边完成 。
3.createInvocableHandlerMethod方法
作用:封装HandlerMethod为ServletInvocableHandlerMethod对象,提供执行方法、绑定参数、处理返回值的场所。
1 2 3 protected ServletInvocableHandlerMethod createInvocableHandlerMethod (HandlerMethod handlerMethod) { return new ServletInvocableHandlerMethod (handlerMethod); }
在创建三个变量(binderFactory、modelFactory、invocableMethod)后,还有三步(这里省略了异步处理): 1.新建传递参数的ModelAndViewContainer容器,并将相应参数设置到Model中, 2.执行请求, 3.请求处理完后进行一些后置处理。
4.invokeHandlerMethod方法
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 protected ModelAndView invokeHandlerMethod (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest (request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this .argumentResolvers != null ) { invocableMethod.setHandlerMethodArgumentResolvers(this .argumentResolvers); } if (this .returnValueHandlers != null ) { invocableMethod.setHandlerMethodReturnValueHandlers(this .returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this .parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer (); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this .ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this .asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this .taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this .callableInterceptors); asyncManager.registerDeferredResultInterceptors(this .deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0 ]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]" ; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null ; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
5.getModelAndView方法
作用:使用ModelAndViewContainer、ModelFactory、NativeWebRequest创建ModelAndView对象,对请求调用进行后处理
1.调用ModelFactory的updateModel方法更新Model 2.根据mavContainer创建MdoelAndView 3.如果mavContainer里的model是RedirectAttributes类型,将其设置到FlashMap。
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 private ModelAndView getModelAndView (ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null ; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView (mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null ) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }
这里的model只有处理器在返回redirect类型的视图才可能是RedirectAttributes类型 ,否则不会是RedirectAttributes类型,也就是说在不返回redirect类型视图的处理器中即使使用RedirectAttributes设置了变量也不会保存到FlashMap中。
3.3ModelAndViewContainer 在 RequestMappingHandlerAdapter 的 invokeHandlerMethod方法 中创建并使用。
ModelAndViewContainer承担着整个请求过程中数据的传递工作。
在处理器中使用了 Model 或者 ModelMap 时ArgumentResolver会传入defaultModel ,它是BindingAwareModelMap类型,既继承了ModelMap又实现了Model接口,所以Model或者ModelMap其实使用的是同一个对象。
处理器中RedirectAttributes类型的参数ArgumentResolver会传入redirectModel ,它实际上是RedirectAttributesModelMap类型。
getModel方法 返回redirectModel的情况下,在处理器中设置到Model的参数就不会被mav使用了(设置SessionAttributes除外)。
getModel方法 返回defaultModel,设置到RedirectAttributes中的参数也将丢弃,也就是说在返回的view不是redirect类型时,即使处理器使用RedirectAttributes参数设置了值也不会传递到下一个请求。
只有将参数设置到Model或者ModelMap里才能使用SessionAttributes缓存,设置到RedirectAttributes里的参数不行。
3.4SessionAttributesHandler和SessionAttributeStore 在 RequestMappingHandlerAdapter 的 getModelFactory方法中创建并缓存到其属性sessionAttributesHandlerCache 中,每个controller对应一个自己的SessionAttributesHandler 。且每个SessionAttributesHandler都封装了其属性sessionAttributeStore。
SessionAttributesHandler用来处理@SessionAttributes注解的参数,来创建SessionAttributesHandler对象。
SessionAttributesHandler的具体存储工作是交给SessionAttributeStore去做的 ,而且使用的统一为 RequestMappingHandlerAdapter 的SessionAttributeStore。SessionAttributeStore并不是保存数据的容器,而是保存数据的工具,具体保存数据的容器使用的是Session。
SessionAttributeHandler是在ModelFactory中使用的。
3.5ModelFactory 是用来维护Model的,具体包含两个功能:1.初始化Model,2.处理器执行后将Model中相应的参数更新到SessionAttributes中。
初始化Model 主要是在处理器执行前将相应数据设置到Model中,是通过调用initModel方法完成的。
initModel方法
1.从sessionAttributes中取出保存的参数,并合并到mavContainer的Model中 2.执行注解了@ModelAttribute的方法并将结果设置到mavContainer的Model中 3.判断既注解了@ModelAttribute又在@SessionAttributes注解中(参数名或者参数类型在注解中设置了)的参数是否已经设置到mavContainer的Model中,如果没有则使用sessionAttributesHandler从sessionAttributeStore中获取并设置到mavContainer中。
第三步跟第一步的区别是第一步 是将当前处理器保存的所有SessionAttributes属性合并到了mavContainer,而第三步 可以使用其它处理器中保存的SessionAttributes属性来设置注解了@ModelAttribute的参数。
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 public void initModel (NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod) throws Exception { Map<String, ?> sessionAttributes = this .sessionAttributesHandler.retrieveAttributes(request); container.mergeAttributes(sessionAttributes); invokeModelAttributeMethods(request, container); for (String name : findSessionAttributeArguments(handlerMethod)) { if (!container.containsAttribute(name)) { Object value = this .sessionAttributesHandler.retrieveAttribute(request, name); if (value == null ) { throw new HttpSessionRequiredException ("Expected session attribute '" + name + "'" , name); } container.addAttribute(name, value); } } }
invokeModelAttributeMethods方法
作用:遍历的方式执行注解了@ModelAttribute的方法并将结果设置到mavContainer的Model中
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 private void invokeModelAttributeMethods (NativeWebRequest request, ModelAndViewContainer container) throws Exception { while (!this .modelMethods.isEmpty()) { InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod(); ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class); if (container.containsAttribute(ann.name())) { if (!ann.binding()) { container.setBindingDisabled(ann.name()); } continue ; } Object returnValue = modelMethod.invokeForRequest(request, container); if (modelMethod.isVoid()) { if (StringUtils.hasText(ann.value())) { if (logger.isDebugEnabled()) { logger.debug("Name in @ModelAttribute is ignored because method returns void: " + modelMethod.getShortLogMessage()); } } continue ; } String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType()); if (!ann.binding()) { container.setBindingDisabled(returnValueName); } if (!container.containsAttribute(returnValueName)) { container.addAttribute(returnValueName, returnValue); } } }
getNameForReturnValue方法
作用:根据方法返回值和返回类型/@ModelAttribute注解获取Model的参数名,此方法主要实现基于@ModelAttribute注解获取Model的参数名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static String getNameForReturnValue (@Nullable Object returnValue, MethodParameter returnType) { ModelAttribute ann = returnType.getMethodAnnotation(ModelAttribute.class); if (ann != null && StringUtils.hasText(ann.value())) { return ann.value(); } else { Method method = returnType.getMethod(); Class<?> containingClass = returnType.getContainingClass(); Class<?> resolvedType = GenericTypeResolver.resolveReturnType(method, containingClass); return Conventions.getVariableNameForReturnType(method, resolvedType, returnValue); } }
Conventions.getVariableNameForReturnType方法
作用:根据方法返回类型 和返回值 获取参数名称。1.如果方法返回类型为Object,则基于返回值获取参数名称 2.如果方法返回类型非Object则基于返回类型获取参数名称
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 public static String getVariableNameForReturnType (Method method, Class<?> resolvedType, @Nullable Object value) { if (Object.class == resolvedType) { if (value == null ) { throw new IllegalArgumentException ( "Cannot generate variable name for an Object return type with null value" ); } return getVariableName(value); } Class<?> valueClass; boolean pluralize = false ; String reactiveSuffix = "" ; if (resolvedType.isArray()) { valueClass = resolvedType.getComponentType(); pluralize = true ; } else if (Collection.class.isAssignableFrom(resolvedType)) { valueClass = ResolvableType.forMethodReturnType(method).asCollection().resolveGeneric(); if (valueClass == null ) { if (!(value instanceof Collection)) { throw new IllegalArgumentException ("Cannot generate variable name " + "for non-typed Collection return type and a non-Collection value" ); } Collection<?> collection = (Collection<?>) value; if (collection.isEmpty()) { throw new IllegalArgumentException ("Cannot generate variable name " + "for non-typed Collection return type and an empty Collection value" ); } Object valueToCheck = peekAhead(collection); valueClass = getClassForValue(valueToCheck); } pluralize = true ; } else { valueClass = resolvedType; ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(valueClass); if (adapter != null && !adapter.getDescriptor().isNoValue()) { reactiveSuffix = ClassUtils.getShortName(valueClass); valueClass = ResolvableType.forMethodReturnType(method).getGeneric().toClass(); } } String name = ClassUtils.getShortNameAsProperty(valueClass); return (pluralize ? pluralize(name) : name + reactiveSuffix); }
更新Model updateModel方法
作用:1.将当前DefaultModel同步到SessionAttributes中,2.如果需要渲染页面,则给Model中相应参数设置BindingResult。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void updateModel (NativeWebRequest request, ModelAndViewContainer container) throws Exception { ModelMap defaultModel = container.getDefaultModel(); if (container.getSessionStatus().isComplete()){ this .sessionAttributesHandler.cleanupAttributes(request); } else { this .sessionAttributesHandler.storeAttributes(request, defaultModel); } if (!container.isRequestHandled() && container.getModel() == defaultModel) { updateBindingResult(request, defaultModel); } }
在处理器中绑定参数时如果参数注释了@Valid或者@Validated ,则会将校验结果设置到跟其相邻的下一个Error或者BindingResult类型的参数中 。
updateModel一共做了两件事,第一件事是维护SessionAttributes的数据,第二件是给Model中需要的参数设置BindingResult,以备视图使用。
3.6ServletInvocableHandlerMethod
ServletInvocableHandlerMethod也是一种HandlerMethod,只是增加了方法执行的功能 ,当然也相应的增加了参数解析、返回值处理等相关功能 。
本节从HandlerMethod开始依次对这三个组件进行分析。
3.6.1HandlerMethod 用于封装Handler和其中具体处理请求的Method ,分别对应其中的bean和method属性 。
如果Handler是String类型,将其变为容器中对应bean的过程在专门的方法createWithResolvedBean中来操作的。
HandlerMethod中属性的含义除了bridgedMethod 外都比较容易理解,只是保存参数的属性parameters使用了可能不太熟悉的类型MethodParameter 。
MethodParameter 里最重要的是method和parameterIndex,有了这两个参数后参数类型、注释等都可以获取到。不过在正常的反射技术里是不知道参数名的,所以这里专门使用了一个参数名查找的组件 parameterNameDiscoverer 。
在 HandlerMethod 中定义了两个内部类来封装参数,一个封装方法调用的参数HandlerMethodParameter ,一个封装方法返回的参数ReturnValueMethodParameter 。
两个类都是MethodParameter的子类,而且ReturnValueMethodParameter还是HandlerMethodParameter的子类,其parameterIndex默认为-1。它们主要使用method和parameterIndex来创建MethodParamter,且它们使用的method都是bridgedMethod 。
bridge method(桥方法)
桥方法作为一个桥将Object为参数的调用转换到了调用String为参数的方法。
在HandlerMethod中的bridgedMethod指的是被桥的方法(注意是bridged而不是bridge),也就是原来的方法。如果不涉及泛型bridgedMethod和method都是同一个方法。
3.6.2InvocableHandlerMethod 继承自HandlerMethod,在父类的基础上添加了调用的功能 (核心),也就是说,InvocableHandlerMethod可以直接调用内部属性method对应的方法(严格来说应该是bridgedMethod)。
方法调用是基于从http请求中解析出来的参数 ,和HandlerMethod中封装的method和bean来通过反射调用的 。
里面有三个属性:
dataBinderFactory:WebDataBinderFactory类型,可以创建WebDataBInder,用于参数解析器ArgumentResolver中。
resolvers:HandlerMethodArgumentResolverComposite类型,用于解析参数。
parameterNameDiscoverer:ParameterNameDiscoverer类型,用来获取参数名,用于MethodParameter中。(注意是在放法调用时解析参数时才将parameterNameDiscoverer从InvocableHandlerMethod设置到MethodParameter对象中)
1.核心调用方法为invokeForRequest
作用:getMethodArgumentValues解析方法参数(底层还是使用方法参数解析器组件解析),doInvoke调用方法
1 2 3 4 5 6 7 8 9 10 public Object invokeForRequest (NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
2.doInvoke方法
作用:使用传入的方法参数执行handlermethod封装的方法。
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 protected Object doInvoke (Object... args) throws Exception { Method method = getBridgedMethod(); try { if (KotlinDetector.isSuspendingFunction(method)) { return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args); } return method.invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(method, getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument" ); throw new IllegalStateException (formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException (formatInvokeError("Invocation failure" , args), targetException); } } }
3.getMethodArgumentValues (重要)
作用:使用请求、mavContainer、providedArgs(一般没有)获取方法参数数组。
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 Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object [parameters.length]; for (int i = 0 ; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this .parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null ) { continue ; } if (!this .resolvers.supportsParameter(parameter)) { throw new IllegalStateException (formatArgumentError(parameter, "No suitable resolver" )); } try { args[i] = this .resolvers.resolveArgument(parameter, mavContainer, request, this .dataBinderFactory); } catch (Exception ex) { if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
InvocableHandlerMethod就是在HandlerMethod基础上添加了方法调用功能 ,而方法调用又需要解析参数,所以又提供了解析参数的功能 。
解析的方法有两种,第一种是在providedArgs里面找,第二种是使用argumentResolvers解析,在RequestMappingHandlerAdapter中的调用并没有提供providedArgs,所以只有使用argumentResolvers解析 。
3.6.3ServletInvocableHandlerMethod 继承自InvocableHandlerMethod,在父类的基础上增加了三个功能:1.对@ResponseStatus注解的支持,2.对返回值的处理,3.对异步处理结果的处理。
对返回值的处理是使用returnValueHandlers属性完成的,它是HandlerMethodReturnValueHandlerComposite类型的属性。
当一个方法注解了@ResponseStatus后,返回的response会使用注释中的Status,如果处理器返回值为空或者注解的reason不为空 ,则将中断处理直接返回(不再渲染页面)。
1.invokeAndHandle方法 (核心)
作用:1.invokeForRequest执行方法并获取方法返回值,2.setResponseStatus将解析的@ResponseStatus设置到响应对象中,3.@ResponseStatus注解时两个情况直接返回无需页面渲染(如果处理器返回值为空或者注解的reason不为空),4.返回值处理用于页面渲染
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 public void invokeAndHandle (ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null ) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true ); return ; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true ); return ; } mavContainer.setRequestHandled(false ); Assert.state(this .returnValueHandlers != null , "No return value handlers" ); try { this .returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
2.setResponseStatus方法
作用:根据HandlerMethod解析好的@ResponseStatus注解内容设置响应对象。
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 private void setResponseStatus (ServletWebRequest webRequest) throws IOException { HttpStatus status = getResponseStatus(); if (status == null ) { return ; } HttpServletResponse response = webRequest.getResponse(); if (response != null ) { String reason = getResponseStatusReason(); if (StringUtils.hasText(reason)) { response.sendError(status.value(), reason); } else { response.setStatus(status.value()); } } webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status); }
3.7HandlerMethodArgumentResolver 用来为处理器解析参数参数,主要用在前面讲过的InvocableHandlerMethod中。
HandlerMethodArgumentResolver接口定义 ,只有两个方法,一个用于判断是否可以解析传入的参数,另一个就是用于实际解析参数。
1 2 3 4 5 6 7 public interface HandlerMethodArgumentResolver { boolean supportsParameter (MethodParameter parameter) ; Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;}
HandlerMethodArgumentResolver实现类一般有两种命名方式,一种是XXXMethodArgumentResolver,另一种是XXXMethodProcessor 。前者表示一个参数解析器,后者除了可以解析参数外还可以处理相应类型的返回值,也就是同时还是后面要讲到的HandlerMethodReturnValueHandle。
另外还有个Adapter,它也不是直接解析参数的,而是用来兼容WebArgumentResolver类型的参数解析器的适配器。
解析器介绍:
AbstractMessageConverterMethodArgumentResolver:使用 HttpMessageConverter 解析request body类型参数的基类 。其实现类有HttpEntityMethodProcessor、RequestPartMethodArgumentResolver、RequestResponseBodyMethodProcessor。
AbstractMessageConverterMethodProcessor:AbstractMessageConverterMethodArgumentResolver的扩展,支持返回值的处理。
HttpEntityMethodProcessor:解析HttpEntity (代表请求对象或者响应对象,包含头和体)和RequestEntity (代表请求对象,还包含请求url和请求类型)类型的参数 。
RequestResponseBodyMethodProcessor:解析注解了@RequestBody的参数 。(核心参数解析器)
RequestPartMethodArgumentResolver:解析注解了@RequestPart或者类型为MultipartFile类型以及javax.servlet.http.Part类型的参数 。
AbstractNamedValueMethodArgumentResolver:解析named value类型的参数 (有name的参数,如cookie、requestParam、requestHeader、pathVariable等)的基类 。
AbstractCookieValueMethodArgumentResolver:是AbstractNamedValueMethodArgumentResolver的子抽象类,解析注解了@CookieValue的参数的基类 。
ServletCookieValueMethodArgumentResolver:是AbstractCookieValueMethodArgumentResolver的子类实现类,实现resolveName方法,具体解析cookieValue 。
ExpressionValueMethodArgumentResolver:解析注解了@Value的参数 ,解析过程在父类的resolveEmbeddedValuesAndExpressions方法完成。主要设置了beanFactory,并用它完成具体解析。
MatrixVariableMethodArgumentResolver:解析注解了@MatrixVariable而且类型不是Map的参数 。
PathVariableMethodArgumentResolver:解析注解了@PathVariable而且类型不是Map的参数 。
RequestHeaderMethodArgumentResolver:解析注解了@RequestHeader而且不是Map类型的参数 。
RequestParamMethodArgumentResolver:解析注解了**@RequestParam的参数、 MultipartFile类型的参数和没有注解的通用类型的参数, 如果注解了@RequestParam且类型为Map的参数必须注解设置了name值否则不使用本解析器。 (核心参数解析器)**
ModelAttributeMethodProcessor:解析注解了@ModelAttribute的参数 ,如果其中的属性annotationNotRequired为true时还可以解析没有注解的非通用类型的参数(但默认为false)。
AbstractWebArgumentResolverAdapter:用作 WebArgumentResolver(接口,不同于HandlerMethodArgumentResolver接口) 解析器的适配器。
ErrorsMethodArgumentResolver:解析Errors类型的参数 。当一个参数绑定出现异常时会自动将异常设置到其相邻的下一个Errors类型的参数,设置方法就是使用了这个解析器,内部是直接从model中获取的。
MapMethodProcessor:解析Map类型参数 (包括ModelMap类型,且同时要求参数上没有任何注解 )。直接返回mavContainer中的model作为参数值。
ModelMethodProcessor:解析Model类型参数 。直接返回mavContainer中的model作为参数值。
RedirectAttributesMethodArgumentResolver:解析RedirectAttributes类型的参数 。新建RedirectAttributesModelMap类型的RedirectAttributes并设置到mavConatiner中,然后返回其作为参数值。
ServletRequestMethodArgumentResolver:解析WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、Locale、TimeZone、InputStream、Reader、HttpMethod、ZoneId类型的参数 ,它们都是使用request获取的。
ServletResponseMethodArgumentResolver:解析ServletResponse、OutputStream、Writer类型的参数 。它们都是使用response获取的。
SessionStatusMethodArgumentResolver:解析SessionStatus类型参数,直接返回mavContainer中的SessionStatus作为参数值。
1.ModelMethodProcessor源码分析 作用:用于解析Model类型的方法参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class ModelMethodProcessor implements HandlerMethodArgumentResolver , HandlerMethodReturnValueHandler { @Override public boolean supportsParameter (MethodParameter parameter) { return Model.class.isAssignableFrom(parameter.getParameterType()); } @Override @Nullable public Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null , "ModelAndViewContainer is required for model exposure" ); return mavContainer.getModel(); } }
通过前面的分析知道,这时Model可能已经保存了一些值,如SessionAttributes中的值、FlashMap中的值、还有@ModelAttribute方法设置的值 。主要是以下方法实现的初始化Model的值。
1 2 mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod);
2.PathVariableMethodArgumentResolver源码分析 作用:解析带@PathVariable注解的方法参数。特别的参数类型为Map时还同时要求@PathVariable注解设置了value值。
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 public final Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); if (resolvedName == null ) { throw new IllegalArgumentException ( "Specified name must not resolve to null: [" + namedValueInfo.name + "]" ); } Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); if (arg == null ) { if (namedValueInfo.defaultValue != null ) { arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); } arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); } else if ("" .equals(arg) && namedValueInfo.defaultValue != null ) { arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } if (binderFactory != null ) { WebDataBinder binder = binderFactory.createBinder(webRequest, null , namedValueInfo.name); try { arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { throw new MethodArgumentConversionNotSupportedException (arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } catch (TypeMismatchException ex) { throw new MethodArgumentTypeMismatchException (arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } if (arg == null && namedValueInfo.defaultValue == null && namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest); } } handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; }
@Value中的value、
@PathVariable中的name、@RequestAttribute中的name、@SessionAttribute中的name、
@RequestHeader中的name和defaultValue、@RequestParam中的name和defaultValue、@CookieValue中的name和defaultValue支持${}与#{}SpEL表达式形式。
以上注解都由AbstractNamedValueMethodArgumentResolver子类来处理。
3.RequestParamMethodArgumentResolver源码分析 RequestMappingHandlerAdapter对象的argumentResolversz属性中包含对应类型的两个对象 。第一个不会解析无注解简单类型参数,第二个会解析无注解简单类型参数。
作用 :
会解析带@RequestParam注解的参数 。
会解析无@RequestPart注解MultipartFile、Part类型 (包括其数组类型和集合类型)的参数 。
会解析无@RequestParam注解简单类型的参数 (包括基本数据类型、基本数据类型对应的包装类型、枚举类型、CharSequence字符序列类型、Date日期类型、Temporal类型即LocalDateTime日期相关类型、URI、URL、Locale、Class类型)。
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 public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor { public boolean supportsParameter (MethodParameter parameter) { if (parameter.hasParameterAnnotation(RequestParam.class)) { if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); return (requestParam != null && StringUtils.hasText(requestParam.name())); } else { return true ; } } else { if (parameter.hasParameterAnnotation(RequestPart.class)) { return false ; } parameter = parameter.nestedIfOptional(); if (MultipartResolutionDelegate.isMultipartArgument(parameter)) { return true ; } else if (this .useDefaultResolution) { return BeanUtils.isSimpleProperty(parameter.getNestedParameterType()); } else { return false ; } } } protected Object resolveName (String name, MethodParameter parameter, NativeWebRequest request) throws Exception { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); if (servletRequest != null ) { Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest); if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) { return mpArg; } } Object arg = null ; MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class); if (multipartRequest != null ) { List<MultipartFile> files = multipartRequest.getFiles(name); if (!files.isEmpty()) { arg = (files.size() == 1 ? files.get(0 ) : files); } } if (arg == null ) { String[] paramValues = request.getParameterValues(name); if (paramValues != null ) { arg = (paramValues.length == 1 ? paramValues[0 ] : paramValues); } } return arg; } }
父类AbstractNamedValueMethodArgumentResolver 关键方法
注意:MethodArgumentResolver 里的resolveArgument方法的参数WebDataBinderFactory是由 InvocableHandlerMethod 的dataBinderFactory属性传入的,而其属性是在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 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 public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver { public final Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); if (resolvedName == null ) { throw new IllegalArgumentException ( "Specified name must not resolve to null: [" + namedValueInfo.name + "]" ); } Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); if (arg == null ) { if (namedValueInfo.defaultValue != null ) { arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); } arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); } else if ("" .equals(arg) && namedValueInfo.defaultValue != null ) { arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } if (binderFactory != null ) { WebDataBinder binder = binderFactory.createBinder(webRequest, null , namedValueInfo.name); try { arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { throw new MethodArgumentConversionNotSupportedException (arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } catch (TypeMismatchException ex) { throw new MethodArgumentTypeMismatchException (arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } if (arg == null && namedValueInfo.defaultValue == null && namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest); } } handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; } private NamedValueInfo getNamedValueInfo (MethodParameter parameter) { NamedValueInfo namedValueInfo = this .namedValueInfoCache.get(parameter); if (NamedValueInfo == null ) { namedValueInfo = createNamedValueInfo(parameter); namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo); this .namedValueInfoCache.put(parameter, namedValueInfo); } return namedValueInfo; } }
4.ServletModelAttributeMethodProcessor源码分析 RequestMappingHandlerAdapter对象的argumentResolvers属性中包含对应类型的两个对象 。第一个不会解析无注解复杂类型参数,第二个会解析无注解复杂类型参数。
作用 :
支持解析带@ModelAttribute注解的方法参数 。
支持解析无@ModelAttribute注解非简单类型的方法参数 。
@ModelAttribute注解方法参数值解析来源,不仅来源于Model中还来源于 请求路径 和 请求参数,且请求路径优于请求参数优于Model。
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 public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver , HandlerMethodReturnValueHandler { public boolean supportsParameter (MethodParameter parameter) { return (parameter.hasParameterAnnotation(ModelAttribute.class) || (this .annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType()))); } public final Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null , "ModelAttributeMethodProcessor requires ModelAndViewContainer" ); Assert.state(binderFactory != null , "ModelAttributeMethodProcessor requires WebDataBinderFactory" ); String name = ModelFactory.getNameForParameter(parameter); ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null ) { mavContainer.setBinding(name, ann.binding()); } Object attribute = null ; BindingResult bindingResult = null ; if (mavContainer.containsAttribute(name)) { attribute = mavContainer.getModel().get(name); } else { try { attribute = createAttribute(name, parameter, binderFactory, webRequest); } catch (BindException ex) { if (isBindExceptionRequired(parameter)) { throw ex; } if (parameter.getParameterType() == Optional.class) { attribute = Optional.empty(); } else { attribute = ex.getTarget(); } bindingResult = ex.getBindingResult(); } } if (bindingResult == null ) { WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null ) { if (!mavContainer.isBindingDisabled(name)) { bindRequestParameters(binder, webRequest); } validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new BindException (binder.getBindingResult()); } } if (!parameter.getParameterType().isInstance(attribute)) { attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); } bindingResult = binder.getBindingResult(); } Map<String, Object> bindingResultModel = bindingResult.getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return attribute; } }
ModelFactory.getNameForParameter(parameter)方法解析
作用:根据 MethodParameter对象 解析方法参数名,即基于参数上的注解或者参数类型解析参数名。
1 2 3 4 5 6 7 8 9 public static String getNameForParameter (MethodParameter parameter) { ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); String name = (ann != null ? ann.value() : null ); return (StringUtils.hasText(name) ? name : Conventions.getVariableNameForParameter(parameter)); }
createAttribute(name, parameter, binderFactory, webRequest)方法解析
作用:根据参数名、参数类型创建方法参数值。(此时未初始化嵌套的参数属性值)。
1.对于**@ModelAttribute注解的参数,且未在mavContainer得Model中发现对应名称的属性时**,会在本方法创建Model的属性值,并作为方法参数值。(本子类实现如请求路径或请求参数存在此参数名的值时以此值作为方法参数值,父类实现不存在时创建Model属性对象)
2.对于没有@ModelAttribute注解非简单类型的参数 ,则会在本方法根据参数类型直接使用反射构造器创建方法参数值对象,后续再使用WebDataBinder来初始化方法参数的属性值。(完全由父类实现创建)
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 protected final Object createAttribute (String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { String value = getRequestValueForAttribute(attributeName, request); if (value != null ) { Object attribute = createAttributeFromRequestValue( value, attributeName, parameter, binderFactory, request); if (attribute != null ) { return attribute; } } return super .createAttribute(attributeName, parameter, binderFactory, request); } protected String getRequestValueForAttribute (String attributeName, NativeWebRequest request) { Map<String, String> variables = getUriTemplateVariables(request); String variableValue = variables.get(attributeName); if (StringUtils.hasText(variableValue)) { return variableValue; } String parameterValue = request.getParameter(attributeName); if (StringUtils.hasText(parameterValue)) { return parameterValue; } return null ; } protected Object createAttributeFromRequestValue (String sourceValue, String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { DataBinder binder = binderFactory.createBinder(request, null , attributeName); ConversionService conversionService = binder.getConversionService(); if (conversionService != null ) { TypeDescriptor source = TypeDescriptor.valueOf(String.class); TypeDescriptor target = new TypeDescriptor (parameter); if (conversionService.canConvert(source, target)) { return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter); } } return null ; }
父类ModelAttributeMethodProcessor的createAttribute方法
作用:1.创建Model属性对象2.创建复杂类型对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected Object createAttribute (String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception { MethodParameter nestedParameter = parameter.nestedIfOptional(); Class<?> clazz = nestedParameter.getNestedParameterType(); Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz); Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest); if (parameter != nestedParameter) { attribute = Optional.of(attribute); } return attribute; }
数据绑定器工厂
核心绑定不同类型参数 的组件ServletRequestDataBinderFactory ,每次调用方法就会创建一个此 WebDataBinderFactory 工厂对象。
ServletRequestDataBinderFactory组件有两个作用:
对于简单 类型,将String类型值(来源于请求)转换 为方法参数值类型。
对于复杂 类型,将string类型值(来源于请求)设置 到方法参数对象的属性中。
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 public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory { public ServletRequestDataBinderFactory (@Nullable List<InvocableHandlerMethod> binderMethods, @Nullable WebBindingInitializer initializer) { super (binderMethods, initializer); } protected ServletRequestDataBinder createBinderInstance ( @Nullable Object target, String objectName, NativeWebRequest request) throws Exception { return new ExtendedServletRequestDataBinder (target, objectName); } } public class InitBinderDataBinderFactory extends DefaultDataBinderFactory { private final List<InvocableHandlerMethod> binderMethods; public InitBinderDataBinderFactory (@Nullable List<InvocableHandlerMethod> binderMethods, @Nullable WebBindingInitializer initializer) { super (initializer); this .binderMethods = (binderMethods != null ? binderMethods : Collections.emptyList()); } public void initBinder (WebDataBinder dataBinder, NativeWebRequest request) throws Exception { for (InvocableHandlerMethod binderMethod : this .binderMethods) { if (isBinderMethodApplicable(binderMethod, dataBinder)) { Object returnValue = binderMethod.invokeForRequest(request, null , dataBinder); if (returnValue != null ) { throw new IllegalStateException ( "@InitBinder methods must not return a value (should be void): " + binderMethod); } } } } protected boolean isBinderMethodApplicable (HandlerMethod initBinderMethod, WebDataBinder dataBinder) { InitBinder ann = initBinderMethod.getMethodAnnotation(InitBinder.class); Assert.state(ann != null , "No InitBinder annotation" ); String[] names = ann.value(); return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName())); } } public class DefaultDataBinderFactory implements WebDataBinderFactory { @Nullable private final WebBindingInitializer initializer; public DefaultDataBinderFactory (@Nullable WebBindingInitializer initializer) { this .initializer = initializer; } public final WebDataBinder createBinder ( NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception { WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest); if (this .initializer != null ) { this .initializer.initBinder(dataBinder, webRequest); } initBinder(dataBinder, webRequest); return dataBinder; } } public interface WebDataBinderFactory { WebDataBinder createBinder (NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception; }
数据绑定器
核心入口方法是bind(ServletRequest request)方法 !
方法位于ServletRequestDataBinder类中。
作用:
收集【请求参数】中的数据创建 ServletRequestParameterPropertyValues 对象,
调用父类addBindValues(mpvs, request)方法收集【请求路径】中的数据填充ServletRequestParameterPropertyValues数据,
调用子类WebDataBinder的doBind(mpvs)方法来真正执行数据绑定。
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 public class ServletRequestDataBinder extends WebDataBinder { public void bind (ServletRequest request) { MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues (request); MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class); if (multipartRequest != null ) { bindMultipart(multipartRequest.getMultiFileMap(), mpvs); } else if (StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.MULTIPART_FORM_DATA_VALUE)) { HttpServletRequest httpServletRequest = WebUtils.getNativeRequest(request, HttpServletRequest.class); if (httpServletRequest != null && HttpMethod.POST.matches(httpServletRequest.getMethod())) { StandardServletPartUtils.bindParts(httpServletRequest, mpvs, isBindEmptyMultipartFiles()); } } addBindValues(mpvs, request); doBind(mpvs); } }
WebDataBinder的doBind(mpvs)方法
作用:1.校验mpvs中的默认字段2.校验mpvs中的空白字段3.将mpvs中的[]名字后缀去掉4.真正执行数据绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Nullable private String fieldMarkerPrefix = DEFAULT_FIELD_MARKER_PREFIX; @Nullable private String fieldDefaultPrefix = DEFAULT_FIELD_DEFAULT_PREFIX; private boolean bindEmptyMultipartFiles = true ; protected void doBind (MutablePropertyValues mpvs) { checkFieldDefaults(mpvs); checkFieldMarkers(mpvs); adaptEmptyArrayIndices(mpvs); super .doBind(mpvs); }
DataBinder的dobind(mpvs)方法
作用:1.校验是否允许绑定2.校验是否必须绑定3.指定数据绑定
是基于BeanWrapperImpl 来实现的bean属性的数据类型转换,更核心的是AbstractNestablePropertyAccessor .java类。
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 protected void doBind (MutablePropertyValues mpvs) { checkAllowedFields(mpvs); checkRequiredFields(mpvs); applyPropertyValues(mpvs); } protected void applyPropertyValues (MutablePropertyValues mpvs) { try { getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields()); } catch (PropertyBatchUpdateException ex) { for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) { getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult()); } } } protected ConfigurablePropertyAccessor getPropertyAccessor () { return getInternalBindingResult().getPropertyAccessor(); } protected AbstractPropertyBindingResult getInternalBindingResult () { if (this .bindingResult == null ) { this .bindingResult = (this .directFieldAccess ? createDirectFieldBindingResult(): createBeanPropertyBindingResult()); } return this .bindingResult; }
BeanWrapperImpl的核心 转换数据类型是基于:ConversionService (TODO:分析BeanWrapperImpl、与WebConversionService组件)
对象参数转换核心:
1 2 3 4 5 6 7 public interface ConversionService { boolean canConvert (@Nullable Class<?> sourceType, Class<?> targetType) ; boolean canConvert (@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) ; <T> T convert (@Nullable Object source, Class<T> targetType) ; Object convert (@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) ; }
核心实现:
5.RequestResponseBodyMethodProcessor源码分析