SpringMVC
来源:互联网 发布:java开发工作描述 编辑:程序博客网 时间:2024/05/01 11:19
运行流程示例一将从一个普通的get请求,到返回视图页面结束为一个过程,并使用源码跟踪。
【JSP】:
<a href="emps">List All Employees</a>//很普通一个a标签,没有传参到后台
【Controller】:
@Controllerpublic class EmployeeHandler { @Autowired private EmployeeDao employeeDao; @Autowired private DepartmentDao departmentDao; /*先执行这个方法*/ @ModelAttribute public void getEmployee(@RequestParam(value="id1",required=false) Integer id, Map<String, Object> map){ if(id != null){ map.put("employee", employeeDao.get(id)); } System.out.println("@ModelAttribute 方法执行"); } /*获取人员列表*/ @RequestMapping("/emps") public String list(Map<String, Object> map){ map.put("employees", employeeDao.getAll()); System.out.println("list method execute..."); return "list"; }// @InitBinder// public void initBinder(WebDataBinder binder){// binder.setDisallowedFields("lastName");// }}
正式开始分析:
项目启动,将会加载web.xml , 随之加载springmvc.xml .
【1】启动项目。。。初始化initStrategies
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context);// initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context);//初始化视图解析器 initFlashMapManager(context); }
看源码注释:
翻译过来就是:初始化servlet所需要使用的策略对象。
/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */
① 初始化HandlerMappings示例:
/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. * 翻译:初始化hadlermapping,这个域名空间中如果没有定义HandlerMapping beans,将会使用默认的BeanNameUrlHandlerMapping */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); //在这里进行初始化!从上下文中拿属性! if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. OrderComparator.sort(this.handlerMappings); //这里进行了排序 } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
- 具体在下面语句进行初始化:
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
其他的初始化类似!
【2】点击链接,发出请求!
进入DispatcherServlet的doDispatcher放法:
- 具体步骤已经在源码中注明!
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. mappedHandler = getHandler(processedRequest); //这里返回一个HandlerExecutionChain! if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //这里返回一个HandlerAdapter,下面就可以开始执行拦截器了! // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { //在这里!执行拦截器额preHandler方法! return; } try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //调用HandlerAdapter的handler方法真正开始执行目标处理方法。。。最终返回MV! } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } //如果mv没有viewName,就使用默认的this.prefix + transformPath(lookupPath) + this.suffix applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); //这里进行拦截器的postHandler方法! } catch (Exception ex) { dispatchException = ex; } //处理转发结果! processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
【下面开始具体详细分析】:【下面开始具体详细分析】:【下面开始具体详细分析】:【下面开始具体详细分析】
① 获取HandlerExecutionChain:
- 根据handlerMapping获取HandlerExecutionChain ;
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } //通过hm获取HEC! HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
- 级联方法1 - 获取handler
@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); //从请求获取handler if (handler == null) { handler = getDefaultHandler(); //如果为空,获取默认的!--springmvc.xml会配置一个默认的servlet--default(为tomcat-web.xml中配置的) } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } return getHandlerExecutionChain(handler, request); /*通过handler和request,将拦截器包装进来,见级联方法2*/ }
看第一行获取handler方法:
Object handler = getHandlerInternal(request);
注释如下:
Look up a handler for the given request, returning null if no specific one is found. This method is called by getHandler; a null return value will lead to the default handler, if one is set. //为给定的请求匹配一个handler,如果没有就返回null;//如果返回值为null,使用默认处理器--default handler!!!
源码如下:
类:public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean
方法:
/** * Look up a handler method for the given request. */ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // lookupPath 为请求url,如"/emps" if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } //创建 handlerMethod,此时handlerMethod拥有属性bean其值为字符串类Handler(如employeeHandler) HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } //如果handlerMethod 不为空,则创建方法隶属的controller bean handler--即将字符串解析为 object bean return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null; }
类:org.springframework.web.servlet.handler.
AbstractHandlerMethodMapping<T>.lookupHandlerMethod()
/** * Look up the best-matching handler method for the current request. * If multiple matches are found, the best match is selected. * @param lookupPath mapping lookup path within the current servlet mapping * @param request the current request * @return the best-matching handler method, or {@code null} if no match * @see #handleMatch(Object, String, HttpServletRequest) * @see #handleNoMatch(Set, String, HttpServletRequest) */ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { //此时matches 为空 [] ; List<Match> matches = new ArrayList<Match>(); //根据请求URL 获取urlMap中与其对应的list对象,如下所示: /*[{[/emps],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]*/ List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { // 添加由match 与handlerMethods.get(mapping)构建的New Match对象于 matches list中 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { /*getMappingComparator : Return a comparator for sorting matching mappings. The returned comparator should sort 'better' matches higher.*/ Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); /*使用构建的comparator 对matches进行排序*/ Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } /*获取最好的匹配对象*/ Match bestMatch = matches.get(0); /*如果matches有多于一个的match,则比较前两个。如果优先级一样,抛出异常*/ if (matches.size() > 1) { Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); //返回优先级最高的bestMatch的handlerMethod对象。 return bestMatch.handlerMethod; } else { return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } }
Match:public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean 的
内部类Match如下:
/** * A thin wrapper around a matched HandlerMethod and its matched mapping for * the purpose of comparing the best match with a comparator in the context * of the current request. */ private class Match { private final T mapping; private final HandlerMethod handlerMethod; private Match(T mapping, HandlerMethod handlerMethod) { this.mapping = mapping; this.handlerMethod = handlerMethod; } @Override public String toString() { return this.mapping.toString(); } } private class MatchComparator implements Comparator<Match> { private final Comparator<T> comparator; public MatchComparator(Comparator<T> comparator) { this.comparator = comparator; } @Override public int compare(Match match1, Match match2) { return this.comparator.compare(match1.mapping, match2.mapping); } }
解释如下:
① 一个简单的包装类,包装了handlerMethod与MappingInfo(保存了请求的数据,如参数,方法,映射及headers等);
② 主要用来根据comparator获取最好的Match对象;
③ 返回其handlerMethod
this.urlMap 如下:
- 保存了url与处理程序方法相关联的映射条件;
- key为URL,值为对应的映射条件
addMatchingMappings执行前:
matches 值:全为null
directPathMatches 值:
- 只有一个由数组组成的对象,size为1,记录了mappingInfo;
addMatchingMappings( ) :
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping<T>.addMatchingMappings()
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { //获取与request对应的重新构建的新的MappingInfo对象 T match = getMatchingMapping(mapping, request); if (match != null) { //根据MappingInfo对象,用对应的handlerMethod构建新的Match对象,添加到 list中 matches.add(new Match(match, handlerMethods.get(mapping))); } } }
注释如下:
Abstract base class for HandlerMapping implementations that define a mapping between a request and a HandlerMethod. //一个抽象基类,其HandlerMapping实现类在请求和处理方法间定义一个映射For each registered handler method, a unique mapping is maintained with subclasses defining the details of the mapping type <T>.//系统中注册的每一个处理方法,都会有一个单独的mapping对象相匹配。
RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfo info, HttpServletRequest request)
- 检查给定的RequestMappingInfo 是否匹配当前请求,并根据具体条件返回一个新的RequestMappingInfo 。
/** * Check if the given RequestMappingInfo matches the current request and * return a (potentially new) instance with conditions that match the * current request -- for example with a subset of URL patterns. * @return an info in case of a match; or {@code null} otherwise. */ @Override protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) { return info.getMatchingCondition(request); }
RequestMappingInfo.getMatchingCondition(HttpServletRequest request)
/** * Checks if all conditions in this request mapping info match the provided request and returns * a potentially new request mapping info with conditions tailored to the current request. * <p>For example the returned instance may contain the subset of URL patterns that match to * the current request, sorted with best matching patterns on top. * @return a new instance in case all conditions match; or {@code null} otherwise */ @Override public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = headersCondition.getMatchingCondition(request); ConsumesRequestCondition consumes = consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = producesCondition.getMatchingCondition(request); if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } PatternsRequestCondition patterns = patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } //返回新的RequestMappingInfo对象 return new RequestMappingInfo(patterns, methods, params, headers, consumes, produces, custom.getCondition()); }
addMatchingMappings执行后:
matches 值:
RequestMappingInfoHandlerMapping.handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request)
@Override protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { super.handleMatch(info, lookupPath, request); String bestPattern; Map<String, String> uriVariables; Map<String, String> decodedUriVariables; Set<String> patterns = info.getPatternsCondition().getPatterns(); if (patterns.isEmpty()) { bestPattern = lookupPath; uriVariables = Collections.emptyMap(); decodedUriVariables = Collections.emptyMap(); } else { bestPattern = patterns.iterator().next(); uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath); decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables); } /*往请求域中设置属性*/ request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables); if (isMatrixVariableContentAvailable()) { Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables); request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars); } if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes(); request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } }
注释如下:
Expose URI template variables, matrix variables, and producible media types in the request.
super.handleMatch:
protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) { request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath); }
return bestMatch.handlerMethod :
以上都在lookupHandlerMethod(lookupPath,request)方法中!!
创建后handlerMethod 的值:
执行HandlerMethod getHandlerInternal()
最后返回结果:
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
handlerMethod.createWithResolvedBean():
/** * If the provided instance contains a bean name rather than an object instance, the bean name is resolved * before a {@link HandlerMethod} is created and returned. */ public HandlerMethod createWithResolvedBean() { Object handler = this.bean; if (this.bean instanceof String) { String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } //返回新的HandlerMethod对象 return new HandlerMethod(this, handler); }
获取的handler:
返回的新的HandlerMethod对象:
/** * Re-create HandlerMethod with the resolved handler. */ private HandlerMethod(HandlerMethod handlerMethod, Object handler) { Assert.notNull(handlerMethod, "handlerMethod is required"); Assert.notNull(handler, "handler is required"); this.bean = handler; this.beanFactory = handlerMethod.beanFactory; this.method = handlerMethod.method; this.bridgedMethod = handlerMethod.bridgedMethod; this.parameters = handlerMethod.parameters; }
最终获取的handler:
- 此时属性bean 不再是字符串,而是object!
为添加拦截器作准备!!!
- 级联方法2–添加interceptor!
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain) ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler); chain.addInterceptors(getAdaptedInterceptors()); //初始化拦截器列表,并为添加到chain中!!! String lookupPath = urlPathHelper.getLookupPathForRequest(request); for (MappedInterceptor mappedInterceptor : mappedInterceptors) { //根据映射URL,添加匹配的拦截器 if (mappedInterceptor.matches(lookupPath, pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); //添加匹配的拦截器于chain中!!! } } return chain; }
- HanlerMapping 有四种:
至此,拿到了hanler和拦截器链!
② 获取HandlerAdapter:
- 根据handlerExecutionChain返回的handler得到HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { //这里,进行匹配!成功则返回! return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
如下图所示,springmvc里面使用了<mvc:annotaion-driven/>
,会有三个默认的adapter!
这里使用的是第三种:RequestMappingHandlerAdapter!
③ 开始执行拦截器的preHandler方法!
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null) { for (int i = 0; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; //执行成功,返回true! }
- 第一个拦截器
拦截的是 DefaultFormattingConversionService,里面涵盖了众多数据格式转换,其值如下!
ConversionService converters = @org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd @org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd @org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 @org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@71933d6c java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@26d6466f java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@4d29efd0 java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@6ebfc8d0 java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@13f17c9e java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@5f0e0edb java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@7c3f6843 java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@32df804e java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@2f5e8a8f java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@1d0bfedd java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@36536500 java.lang.String -> com.atguigu.springmvc.crud.entities.Employee : com.atguigu.springmvc.converters.EmployeeConverter@7cd76237 java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@3daa3554 java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@67daca94 java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@79a5b7b4 java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@6f609af9 java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@7119087d java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@1bdbbaab java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@40c19080 java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@257db177 java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@545532da java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@7e896e10 java.util.Date -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$DateToCalendarConverter@70991d56 java.util.Locale -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@227c808d java.util.Properties -> java.lang.String : org.springframework.core.convert.support.PropertiesToStringConverter@76bc3ed6 java.util.UUID -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@63f5e4b6 org.springframework.core.convert.support.ArrayToArrayConverter@7abb0257 org.springframework.core.convert.support.ArrayToCollectionConverter@247a9bff org.springframework.core.convert.support.ArrayToObjectConverter@51ad65f7 org.springframework.core.convert.support.ArrayToStringConverter@5704ce99 org.springframework.core.convert.support.ByteBufferConverter@71f84d01 org.springframework.core.convert.support.ByteBufferConverter@71f84d01 org.springframework.core.convert.support.CollectionToArrayConverter@6d97950e org.springframework.core.convert.support.CollectionToCollectionConverter@b96dcb4 org.springframework.core.convert.support.CollectionToObjectConverter@3a5367af org.springframework.core.convert.support.CollectionToStringConverter@648f53c8 org.springframework.core.convert.support.FallbackObjectToStringConverter@310ab67f org.springframework.core.convert.support.IdToEntityConverter@6487b71b,org.springframework.core.convert.support.ObjectToObjectConverter@a06812d org.springframework.core.convert.support.MapToMapConverter@5d73b35d org.springframework.core.convert.support.ObjectToArrayConverter@4f016505 org.springframework.core.convert.support.ObjectToCollectionConverter@39bc3013 org.springframework.core.convert.support.StringToArrayConverter@7c97cb70 org.springframework.core.convert.support.StringToCollectionConverter@7dc5a30b
- 第二个拦截器
自定义拦截器
- 执行其preHandler方法:
- 第三个拦截器
i18n拦截器
至此,拦截器的preHandler方法执行完毕!!
开始执行真正的目标方法!
———————-RequestMappingHandlerAdapter.handle()方法!————————————-
④ ha.handle–超级重要的一个方法
主要有这样几个功能:
① 对数据进行格式化转换和校验;
② 尝试调用@ModelAttribute注解的方法;
③ 为你的目标方法参数赋值;
④ 执行你的目标方法;
⑤ 拿到你方法的返回值。。最终拿到一个MV
// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
点击可以看到,其有五类实现;上面已经说明,实际获取的是RequestMappingHandlerAdapter !
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { //...}
其中mappedHandler.getHandler( ):
- 级联方法3-
ModelAndView handle()
/** * {@inheritDoc} <p>This implementation expects the handler to be an {@link HandlerMethod}. */ @Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); //调用handleInternal 方法--见级联方法4 }
- 级联方法4-
ModelAndView handleInternal()
这个方法名字很有意思,“处理内部的”!
@Override protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //判断有没有sessionAttributes if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { // Always prevent caching in case of session attribute management. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { // Uses configured default cacheSeconds setting. checkAndPrepare(request, response, true); } // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandleMethod(request, response, handlerMethod); } } } return invokeHandleMethod(request, response, handlerMethod); //执行目标方法--见级联方法5 }
- 级联方法5-
ModelAndView invokeHandleMethod()
——我要开始执行目标方法啦!—-最后还要回到这个方法!!!
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); /*获取数据绑定工厂*/ WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); /*获取model工厂*/ ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); /*为请求映射的方法配置属性策略,--请看级联方法6*/ ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); /* 创建一个新的mav容器实例 */ ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); /*请求域中的map对象放到容器中*/ modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); /*初始化model-请看级联方法7--这个方法很重要!!!注解@ModelAttribute方法就是在这里被调用!!!*/ mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); final 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(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } /*请看级联方法3-3 这里的invokeAndHandle为ServletInvocableHandlerMethod.invokeAndHandle*/ requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } /* 这里这里!!! 拿到最新的MV!!! */ return getModelAndView(mavContainer, modelFactory, webRequest); }
- 级联方法6
ServletInvocableHandlerMethod createRequestMappingMethod()
- 级联方法6
private ServletInvocableHandlerMethod createRequestMappingMethod( HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { ServletInvocableHandlerMethod requestMethod; requestMethod = new ServletInvocableHandlerMethod(handlerMethod); requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); //设置方法参数解析器 requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); //设置方法返回值处理器 requestMethod.setDataBinderFactory(binderFactory); //设置数据绑定工厂 requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); //设置参数名发现者 return requestMethod; }
- 级联方法7
void initModel
- 级联方法7
————上面说了,你的@ModelAttribute方法就是在这里被调用!!!
/** * Populate the model in the following order: * <ol> * <li>Retrieve "known" session attributes -- i.e. attributes listed via * {@link SessionAttributes @SessionAttributes} and previously stored in * the in the model at least once * //尝试从session中获取attribute * <li>Invoke {@link ModelAttribute @ModelAttribute} methods * //调用该使用@ModelAttribute的方法! * <li>Find method arguments eligible as session attributes and retrieve * them if they're not already present in the model * //如果model没有方法参数对应的model,就从session里面获取 * </ol> * @param request the current request * @param mavContainer contains the model to be initialized * @param handlerMethod the method for which the model is initialized * @throws Exception may arise from {@code @ModelAttribute} methods */ public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod) throws Exception {//从session里面获取Map<String, ?> attributesInSession/*Retrieve "known" attributes from the session, i.e. attributes listed by name in @SessionAttributes or attributes previously stored in the model that matched by type.*/ Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request); mavContainer.mergeAttributes(attributesInSession); //放入modelmap //见级联方法8 invokeModelAttributeMethods(request, mavContainer); //!!!注意 ,执行ModelAttributeMethods(即,有@ModelAttribute注解的方法) for (String name : findSessionAttributeArguments(handlerMethod)) { if (!mavContainer.containsAttribute(name)) { Object value = this.sessionAttributesHandler.retrieveAttribute(request, name); if (value == null) { throw new HttpSessionRequiredException("Expected session attribute '" + name + "'"); } mavContainer.addAttribute(name, value); } } }
- 级联方法8
void invokeModelAttributeMethods()
- 级联方法8
【! 真正开始执行 @ModelAttribute注解的方法!】
/** * Invoke model attribute methods to populate the model. Attributes are * added only if not already present in the model. */ private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception { for (InvocableHandlerMethod attrMethod : this.attributeMethods) { //获取注解的value值!!! String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value(); if (mavContainer.containsAttribute(modelName)) { continue; } //在给定请求的上下文中解析参数值后调用该方法。/* 这里InvocableHandlerMethod.invokeForRequest;这里这个返回值只是为了下面的if方法进行判断,并不会当成视图!!!只会对MV有作用--见级联方法9*/ Object returnValue = attrMethod.invokeForRequest(request, mavContainer); /*Returns true if the method return type is void, false otherwise.如果返回类型不为空,将执行下面的方法;即可以返回一个对象,那么SpringMVC将会根据对象类型,对象值,放modelmap中一个key:value*/ if (!attrMethod.isVoid()){ String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType()); if (!mavContainer.containsAttribute(returnValueName)) { mavContainer.addAttribute(returnValueName, returnValue); } } } }
可以看到方法名,参数个数及类型等信息!
- 级联方法9
Object invokeForRequest
- 级联方法9
—-注意,现在是为@ModelAttribute方法从请求里面解析参数值并赋于方法对应参数!!!
/** * Invoke the method after resolving its argument values in the context of the given request. <p>Argument * values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs} * parameter however may supply argument values to be used directly, i.e. without argument resolution. * Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or * a thrown exception instance. Provided argument values are checked before argument resolvers. * @param request the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type, not resolved * @return the raw value returned by the invoked method * @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception */ public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //获取方法参数值(使用request域中属性对象为方法参数赋值)--见级联方法10 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Invoking ["); sb.append(this.getBeanType().getSimpleName()).append("."); sb.append(getMethod().getName()).append("] method with arguments "); sb.append(Arrays.asList(args)); logger.trace(sb.toString()); } /*根据拿到的解析后的方法参数值,调用目标方法!!!拿到返回的结果;*/ Object returnValue = invoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]"); } return returnValue; }
- 级联方法10
Object[] getMethodArgumentValues
- 级联方法10
这里返回一个object数组
方法参数值数组:解析从request中获取的值,为对应的方法参数赋值,然后返回!
/** * Get the method argument values for the current request. * 从当前请求中获取方法参数值 */ private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(parameter, getBean().getClass()); //试图从提供的参数值列表中解析方法参数。 args[i] = resolveProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (this.argumentResolvers.supportsParameter(parameter)) { //使用参数解析器解析方法参数!!!!参数解析过程要开始了 try { args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex); } throw ex; } } if (args[i] == null) { String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i); throw new IllegalStateException(msg); } } return args; }
这里说明一下参数解析过程:
①Object org.springframework.web.method.support.InvocableHandlerMethod.resolveProvidedArgument(){/*试图从提供的参数值列表中解析方法参数。*/ args[i] = resolveProvidedArgument(parameter, providedArgs);}/*如果上面获取不到值,则从下面获取*/① Object org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(){args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);/*返回到Object org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest*/}③Object org.springframework.web.method.support.HandlerMethodArgumentResolver.resolveArgument(){return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);//返回到②}/*【 此时resolver 为RequestParamMethodArgumentResolver;这里针对不同方法参数类型可能有所不同!!!】*/以下为下面这个方法的注释:/*Resolves a method parameter into an argument value from a given request. --将方法参数从给定的请求转换为参数值。A ModelAndViewContainer provides access to the model for the request.-- 针对该请求,MV容器提供了一个通道使其可以使用model对象。 A WebDataBinderFactory provides a way to create a WebDataBinder instance when needed for data binding and type conversion purposes. --当需要数据绑定或者类型转换、格式化时,WebDataBinder工厂提供了一个通道去创建一个WebDataBinder instance*/【也就是说,你的数据绑定和类型转换,是在这里!!!】④ 调用父类的org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(){ /*拿到参数类型*/ Class<?> paramType = parameter.getParameterType(); /*拿到参数值信息*/ NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);/*Resolves the given parameter type and value name into an argument value.意思是根据给定的参数类型和注解使用的value name,从request中获取对应的值,赋予方法参数!!!*/ Object arg = resolveName(namedValueInfo.name, parameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } else if (namedValueInfo.required) { handleMissingValue(namedValueInfo.name, parameter); } arg = handleNullValue(namedValueInfo.name, arg, paramType); } else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } if (binderFactory != null) { /*根据请求对象和 id1(方法参数的key) 创建binder对象--见数据绑定-1*/ WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); /*Convert the value to the required type (if necessary from a String). 根据参数类型对arg进行数据格式转换*/ arg = binder.convertIfNecessary(arg, paramType, parameter); } /*Invoked after a value is resolved.在值解析后被调用--解析完id1了,arg为null,但是也要返回啊*/ handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; /*返回到③*/}
拿到的参数值信息如下所示,默认值为null,name属性为id1(@RequestParam(value=”id1”,required=false)):
数据流程绑定-1
/** * Create a new {@link WebDataBinder} for the given target object and * initialize it through a {@link WebBindingInitializer}. * @throws Exception in case of invalid state or arguments */ @Override public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception { /*创建dataBinder实例,target此时为null,objectName为 id1 ; 其中createBinderInstance = return new ExtendedServletRequestDataBinder(target, objectName); */ WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest); if (this.initializer != null) { //初始化Binder --见数据绑定流程-2 this.initializer.initBinder(dataBinder, webRequest); } //进一步初始化创建的数据:Extension point to further initialize the created data binder instance (e.g. with @InitBinder methods) after "global" initializaton via WebBindingInitializer. initBinder(dataBinder, webRequest); return dataBinder; }
数据绑定流程-2
@Override public void initBinder(WebDataBinder binder, WebRequest request) { binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths); if (this.directFieldAccess) { binder.initDirectFieldAccess(); } if (this.messageCodesResolver != null) { binder.setMessageCodesResolver(this.messageCodesResolver); } if (this.bindingErrorProcessor != null) { binder.setBindingErrorProcessor(this.bindingErrorProcessor); } //validator!!!数据校验 if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) { binder.setValidator(this.validator); } //conversionService !!!数据转换和格式化 if (this.conversionService != null) { binder.setConversionService(this.conversionService); } if (this.propertyEditorRegistrars != null) { for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) { propertyEditorRegistrar.registerCustomEditors(binder); } } }
此时的dataBinder如下:
这时回到Object resolveArgument( )方法,即参数解析的最后一个过程:
@Override public final Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Class<?> paramType = parameter.getParameterType(); NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); Object arg = resolveName(namedValueInfo.name, parameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } else if (namedValueInfo.required) { handleMissingValue(namedValueInfo.name, parameter); } arg = handleNullValue(namedValueInfo.name, arg, paramType); } else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) { arg = resolveDefaultValue(namedValueInfo.defaultValue); } if (binderFactory != null) { /*创建binder对象*/ WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); /* 尝试进行数据格式转换 */ arg = binder.convertIfNecessary(arg, paramType, parameter); } /*Invoked after a value is resolved*/ handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; //返回解析到的参数值 }
现在回到 级联方法9Object invokeForRequest
!!
此时的args如下图所示:
getEmployee方法的参数值解析完毕:id 为null,map为默认值 BindingAwareModelMap!
开始执行@ModelAttribute注解的方法(getEmployee)
Object returnValue = invoke(args);
如下图所示,现在才开始执行该方法,参数值已经解析过了!!
再次回到级联方法9Object invokeForRequest
!!
此时方法的返回值为null(getEmployee方法没有返回值)
Object returnValue = invoke(args);//该句调用真正的@ModelAttribute注解的方法,开始执行你的getEmployee!!!
- 这里返回值为null
回到级联方法8void invokeModelAttributeMethods()
- returnValue = null:
- 这里的returnValue 只是为了下面的 if 方法判断使用,不会返回!!!
回到级联方法7void initModel
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod) throws Exception { Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request); mavContainer.mergeAttributes(attributesInSession); invokeModelAttributeMethods(request, mavContainer);/*开始继续从这里执行:如果session中有@ModelAttribute参数对应的key,那么从session中获取该value,放到modelmap中(进而放到mav容器中);如果有key,但是没有value,则会抛出异常!!!*/ for (String name : findSessionAttributeArguments(handlerMethod)) { if (!mavContainer.containsAttribute(name)) { Object value = this.sessionAttributesHandler.retrieveAttribute(request, name); if (value == null) { throw new HttpSessionRequiredException("Expected session attribute '" + name + "'"); } mavContainer.addAttribute(name, value); } } }
回到级联方法3-ModelAndView invokeHandleMethod()
!!!
/** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} if view resolution is required. */ private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); //终于从这里出来了,开始执行下面的方法。@ModelAttribute方法已经调用,MV已经有了初步值!!! modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); final 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(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } //Invokes the method and handles the return value through a registered HandlerMethodReturnValueHandler. //*调用的方法和处理返回值通过注册的handlermethodreturnvaluehandler。invokeAndHandle将会调用父类的invokeForRequest请看级联方法10*/ requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); }
再一次重复为目标方法参数赋值的过程!但这时方法已经成为了list,就是真正匹配你的requestMapping那个方法!!!
【执行调用的目标方法时,总要事先为目标方法的参数赋值。@ModelAttribute注解的方法如此,普通的目标方法也如此!】
具体过程如下:
【开始调用你的目标方法】
此时class : .ServletInvocableHandlerMethod
看注释:Invokes the method and handles the return value through a registered
–意思是调用这个方法,并通过注册的handler 处理返回值!!!
级联方法10 void invokeAndHandle
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //Invoke the method after resolving its argument values in the context of the given request. //将会调用父类的该方法(InvocableHandlerMethod) Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
……..go on!
继续解析目标方法的参数过程!
public Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]"); //注意这里 resolver!!!已经变成了MapMethodProcessor return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
………..继续解析参数!!!
。。。。继续。。。直到调用list方法!
此时,args改变!
returnValue 改变!
看到没? returnValue 不再是null 而是你方法返回的视图名! list!!
处理返回值–再次回到级联方法10void invokeAndHandle
public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); //如果返回值为空。。 if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { //这里这里这里!!!返回值不为空开始处理返回值!!!见下属级联方法11 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
可以看到,有12个处理返回值的handler,这里使用的是org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite@1f5a0bc0
级联方法11
/** * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it. * @exception IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found. */ @Override public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]"); // Handle the given return value by adding attributes to the model and setting a view or setting the ModelAndViewContainer.setRequestHandled flag to true to indicate the response has been handled directly. handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); //见下属级联方法12 }
此时的handler为:ViewNameMethodReturnValueHandler
级联方法12–真正处理返回值的方法:
@Override public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { return; } else if (returnValue instanceof String) { //这里!!!将返回值作为视图名! String viewName = (String) returnValue; mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); } }
mavContainer也已经有了employee list
(因为在list方法里面手动放入了啊,这也说明另外一个问题,无论你方法中使用的是map还是model还是mv,那么最终都会对应一个对象,BindingAwareModelMap!!!)
处理完方法返回值了,再次回到级联方法3-ModelAndView RequestMappingHandlerAdapter.invokeHandleMethod()
千辛万苦拿到MV
此时的MV已经包含初步的视图名和model
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { /* 注意这里 更新model 见下属级联方法13*/ modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }
级联方法13
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception { if (mavContainer.getSessionStatus().isComplete()){ this.sessionAttributesHandler.cleanupAttributes(request); } else { this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel()); } /*Whether the request is handled directly.*/ if (!mavContainer.isRequestHandled()) { updateBindingResult(request, mavContainer.getModel()); /*Add BindingResult attributes to the model for attributes that require it. 见下属级联方法14*/ } }
级联方法14
*/ private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception { List<String> keyNames = new ArrayList<String>(model.keySet()); for (String name : keyNames) { Object value = model.get(name); if (isBindingCandidate(name, value)) { String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name; if (!model.containsAttribute(bindingResultKey)) { WebDataBinder dataBinder = binderFactory.createBinder(request, value, name); //看这里看这里!!!从dataBingder拿属性放到model里面!!! model.put(bindingResultKey, dataBinder.getBindingResult()); } } } }
返回到级联方法2-ModelAndView handleInternal()
!!!
@Override protected final ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { // Always prevent caching in case of session attribute management. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { // Uses configured default cacheSeconds setting. checkAndPrepare(request, response, true); } // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandleMethod(request, response, handlerMethod); } } } //Invoke the RequestMapping handler method preparing a ModelAndView if view resolution is required return invokeHandleMethod(request, response, handlerMethod); }
ModelAndView 已经彻底准备好了!!!
回到级联方法1-ModelAndView handle()
至此,HandlerAdapter的handle方法处理完毕!!!
回到DispatcherServlet的doDispatcher方法!
⑤ 执行拦截器的postHandle方法!!
mappedHandler.applyPostHandle(processedRequest, response, mv);
/** * Apply postHandle methods of registered interceptors. */ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { if (getInterceptors() == null) { return; } //拦截器执行顺序颠倒!!! for (int i = getInterceptors().length - 1; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; //执行postHanle方法!! interceptor.postHandle(request, response, this.handler, mv); } }
⑥ 执行处理转发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { //视图渲染!!!Render the given ModelAndView.请往下看级联方法15 /* This is the last stage in handling a request. It may involve resolving the view by name.*/ render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
级联方法15-void render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = this.localeResolver.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // We need to resolve the view name. //通过视图解析器,将逻辑视图转换为物理视图 view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException( "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } try { //在这里进行视图渲染 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex); } throw ex; } }
看,JstlView,name为list,URL!!
进行真正的视图渲染!
view.render(mv.getModelInternal(), request, response);
注释如下:
Render the view given the specified model. --使用给定的model渲染视图The first step will be preparing the request: In the JSP case, this would mean setting model objects as request attributes.--第一步将model objects 设置为 request attributes---所以你的model默认是在request中!!! The second step will be the actual rendering of the view, for example including the JSP via a RequestDispatcher. --第二部才是真正的视图渲染,例如 请求转发到一个JSP!
还没完!
还要执行拦截器的afterCompletion!
mappedHandler.triggerAfterCompletion(request, response, null);
具体方法如下:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { if (getInterceptors() == null) { return; } for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } }
执行次序为从后到前:
好了,结束了,接下来是DispatcherServlet.doService()!
- SpringMVC
- springmvc
- SpringMVC
- SpringMVC
- springMvc
- springMVC
- springmvc
- springMVC
- springMVC
- springmvc
- SpringMVC
- SpringMVC
- springMvc
- springmvc
- springmvc
- SpringMVC
- Springmvc
- springmvc
- 分数转换
- Java多线程线程池(4)--线程池的五种状态
- 配置红帽系列yum源
- CDOJ 215 吴队长征婚 DFS+剪枝
- 递归算法改进---表存储代替冗余递推
- SpringMVC
- 父窗口中获取iframe中的元素
- SpringMVC-学习笔记(1)——理解MVC及快速入门
- 理解Android中的LayoutInflater
- 2016年中国软件产业分析报告
- MIT-BIH心率失常数据提取及部分MATLAB程序解释
- (转)推荐几款实用的Android Studio 插件
- WebGL学习系列-基础矩阵变换
- 2013北邮网研院上机题