說在前面java
本次主要介紹DispatcherServlet,關注」天河聊架構「更需精彩。web
springmvc配置解析spring
上次介紹了執行handler的抽象默認實現。瀏覽器
簡單實現,進入到這個方法org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#handle緩存
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 請求處理-》 ((HttpRequestHandler) handler).handleRequest(request, response); return null; }
進入到這個方法org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#handleRequestcookie
@Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取請求轉發對象 RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName); if (rd == null) { throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" + this.defaultServletName + "'"); } // 請求轉發 rd.forward(request, response); }
就是直接request拿到請求轉發器執行轉發。session
重點來了,基於@RequestMapping的業務handler執行,進入到這個方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#handle架構
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Class<?> clazz = ClassUtils.getUserClass(handler); // 是否綁定了session緩存 Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz); if (annotatedWithSessionAttributes == null) { // 解析@SessionAttributes註解 annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null); this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes); } if (annotatedWithSessionAttributes) { // 檢查session和瀏覽器緩存配置 -》 checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { 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 invokeHandlerMethod(request, response, handler); } } } return invokeHandlerMethod(request, response, handler); }
進入到這個方法org.springframework.web.servlet.support.WebContentGenerator#checkAndPrepare(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int, boolean)mvc
@Deprecated protected final void checkAndPrepare( HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified) throws ServletException { checkRequest(request); // 緩存設置 applyCacheSeconds(response, cacheSeconds); }
往上返回這個方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#invokeHandlerMethodapp
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 根據handler找到業務方法解析器 -》 ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); // 根據請求找到執行的業務方法 -》 Method handlerMethod = methodResolver.resolveHandlerMethod(request); ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); ServletWebRequest webRequest = new ServletWebRequest(request, response); ExtendedModelMap implicitModel = new BindingAwareModelMap(); // 執行業務方法返回結果 -》 Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); // 獲取modelAndView對象 -》 ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); // 更新model methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); return mav; }
進入這個方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#getMethodResolver
private ServletHandlerMethodResolver getMethodResolver(Object handler) { Class<?> handlerClass = ClassUtils.getUserClass(handler); // 從緩存中獲取servletHandler方法解析器 ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); if (resolver == null) { synchronized (this.methodResolverCache) { resolver = this.methodResolverCache.get(handlerClass); if (resolver == null) { resolver = new ServletHandlerMethodResolver(handlerClass); this.methodResolverCache.put(handlerClass, resolver); } } } return resolver; }
往上返回這個方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver#resolveHandlerMethod
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException { // 找到請求路徑-》 String lookupPath = urlPathHelper.getLookupPathForRequest(request); Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath); Map<RequestSpecificMappingInfo, Method> targetHandlerMethods = new LinkedHashMap<RequestSpecificMappingInfo, Method>(); Set<String> allowedMethods = new LinkedHashSet<String>(7); String resolvedMethodName = null; for (Method handlerMethod : getHandlerMethods()) { RequestSpecificMappingInfo mappingInfo = new RequestSpecificMappingInfo(this.mappings.get(handlerMethod)); boolean match = false; if (mappingInfo.hasPatterns()) { for (String pattern : mappingInfo.getPatterns()) { if (!hasTypeLevelMapping() && !pattern.startsWith("/")) { pattern = "/" + pattern; } // 解析組合路徑-》 String combinedPattern = getCombinedPattern(pattern, lookupPath, request); if (combinedPattern != null) { if (mappingInfo.matches(request)) { match = true; mappingInfo.addMatchedPattern(combinedPattern); } else { // 請求方法不匹配-》 if (!mappingInfo.matchesRequestMethod(request)) { allowedMethods.addAll(mappingInfo.methodNames()); } break; } } } mappingInfo.sortMatchedPatterns(pathComparator); } else if (useTypeLevelMapping(request)) { String[] typeLevelPatterns = getTypeLevelMapping().value(); for (String typeLevelPattern : typeLevelPatterns) { if (!typeLevelPattern.startsWith("/")) { typeLevelPattern = "/" + typeLevelPattern; } boolean useSuffixPattern = useSuffixPattern(request); if (getMatchingPattern(typeLevelPattern, lookupPath, useSuffixPattern) != null) { if (mappingInfo.matches(request)) { match = true; mappingInfo.addMatchedPattern(typeLevelPattern); } else { if (!mappingInfo.matchesRequestMethod(request)) { allowedMethods.addAll(mappingInfo.methodNames()); } break; } } } mappingInfo.sortMatchedPatterns(pathComparator); } else { // No paths specified: parameter match sufficient. 請求方法、參數、header匹配 match = mappingInfo.matches(request); if (match && mappingInfo.getMethodCount() == 0 && mappingInfo.getParamCount() == 0 && resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) { match = false; } else { // 請求方法不匹配 if (!mappingInfo.matchesRequestMethod(request)) { allowedMethods.addAll(mappingInfo.methodNames()); } } } if (match) { Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { if (methodNameResolver != null && !mappingInfo.hasPatterns()) { if (!oldMappedMethod.getName().equals(handlerMethod.getName())) { if (resolvedMethodName == null) { // 獲取方法名-》 resolvedMethodName = methodNameResolver.getHandlerMethodName(request); } if (!resolvedMethodName.equals(oldMappedMethod.getName())) { oldMappedMethod = null; } if (!resolvedMethodName.equals(handlerMethod.getName())) { if (oldMappedMethod != null) { targetHandlerMethods.put(mappingInfo, oldMappedMethod); oldMappedMethod = null; } else { targetHandlerMethods.remove(mappingInfo); } } } } if (oldMappedMethod != null) { throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" + oldMappedMethod + ", " + handlerMethod + "}. If you intend to handle the same path in multiple methods, then factor " + "them out into a dedicated handler class with that path mapped at the type level!"); } } } } if (!targetHandlerMethods.isEmpty()) { List<RequestSpecificMappingInfo> matches = new ArrayList<RequestSpecificMappingInfo>(targetHandlerMethods.keySet()); RequestSpecificMappingInfoComparator requestMappingInfoComparator = new RequestSpecificMappingInfoComparator(pathComparator, request); Collections.sort(matches, requestMappingInfoComparator); RequestSpecificMappingInfo bestMappingMatch = matches.get(0); String bestMatchedPath = bestMappingMatch.bestMatchedPattern(); if (bestMatchedPath != null) { extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request); } return targetHandlerMethods.get(bestMappingMatch); } else { if (!allowedMethods.isEmpty()) { throw new HttpRequestMethodNotSupportedException(request.getMethod(), StringUtils.toStringArray(allowedMethods)); } throw new org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException( lookupPath, request.getMethod(), request.getParameterMap()); } }
進入方法org.springframework.web.util.UrlPathHelper#getLookupPathForRequest
public String getLookupPathForRequest(HttpServletRequest request) { // Always use full path within current servlet context? 老是在當前servlet上下文中使用完整路徑? -》 if (this.alwaysUseFullPath) { return getPathWithinApplication(request); } // Else, use path within current servlet mapping if applicable 不然,在當前servlet映射中使用path(若是適用) String rest = getPathWithinServletMapping(request); if (!"".equals(rest)) { return rest; } else { return getPathWithinApplication(request); } }
這裏介紹過了。
返回方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver#getCombinedPattern
private String getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) { // 是否使用前綴匹配 boolean useSuffixPattern = useSuffixPattern(request); // controller上是否有映射 -》 if (useTypeLevelMapping(request)) { String[] typeLevelPatterns = getTypeLevelMapping().value(); for (String typeLevelPattern : typeLevelPatterns) { // 若是controller上的映射前面沒有/自動拼接 if (!typeLevelPattern.startsWith("/")) { typeLevelPattern = "/" + typeLevelPattern; } // 解析controller上和方法上都有映射 String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern); // 獲取映射 -》 String matchingPattern = getMatchingPattern(combinedPattern, lookupPath, useSuffixPattern); if (matchingPattern != null) { return matchingPattern; } } return null; } String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) { String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern); String matchingPattern = getMatchingPattern(combinedPattern, lookupPath, useSuffixPattern); if (matchingPattern != null && !matchingPattern.equals(bestMatchingPattern)) { return matchingPattern; } } return getMatchingPattern(methodLevelPattern, lookupPath, useSuffixPattern); }
進入方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver#useTypeLevelMapping
private boolean useTypeLevelMapping(HttpServletRequest request) { if (!hasTypeLevelMapping() || ObjectUtils.isEmpty(getTypeLevelMapping().value())) { return false; } Object value = request.getAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING); return (value != null) ? (Boolean) value : Boolean.TRUE; }
返回方法org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.RequestMappingInfo#matchesRequestMethod
public boolean matchesRequestMethod(HttpServletRequest request) { return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request); }
返回方法org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver#getHandlerMethodName
@Override public final String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException { // 獲取請求路徑 String urlPath = this.urlPathHelper.getLookupPathForRequest(request); // 根據url路徑獲取請求handler的名稱 String name = getHandlerMethodNameForUrlPath(urlPath); if (name == null) { throw new NoSuchRequestHandlingMethodException(urlPath, request.getMethod(), request.getParameterMap()); } if (logger.isDebugEnabled()) { logger.debug("Returning handler method name '" + name + "' for lookup path: " + urlPath); } return name; }
返回方法org.springframework.web.bind.annotation.support.HandlerMethodInvoker#invokeHandlerMethod
public final Object invokeHandlerMethod(Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { // 橋接模式 Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); try { boolean debug = logger.isDebugEnabled(); for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { // 從session中獲取參數值 Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); if (attrValue != null) { implicitModel.addAttribute(attrName, attrValue); } } for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); // 解析要執行的方法 -》 Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); } String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { continue; } ReflectionUtils.makeAccessible(attributeMethodToInvoke); // 執行handler Object attrValue = attributeMethodToInvoke.invoke(handler, args); if ("".equals(attrName)) { // 解析返回類型 Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); // 根據參數值找到返回類型 attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); } if (!implicitModel.containsAttribute(attrName)) { implicitModel.addAttribute(attrName, attrValue); } } // 解析參數-》 Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking request handler method: " + handlerMethodToInvoke); } ReflectionUtils.makeAccessible(handlerMethodToInvoke); // 執行handler return handlerMethodToInvoke.invoke(handler, args); } catch (IllegalStateException ex) { // Internal assertion failed (e.g. invalid signature): // throw exception with full handler method context... throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); } catch (InvocationTargetException ex) { // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... ReflectionUtils.rethrowException(ex.getTargetException()); return null; } }
進入方法org.springframework.web.bind.annotation.support.HandlerMethodInvoker#resolveHandlerArguments
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { // 獲取controller方法的參數類型 Class<?>[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; for (int i = 0; i < args.length; i++) { MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; String headerName = null; boolean requestBodyFound = false; String cookieName = null; String pathVarName = null; String attrName = null; boolean required = false; String defaultValue = null; boolean validate = false; Object[] validationHints = null; int annotationsFound = 0; Annotation[] paramAnns = methodParam.getParameterAnnotations(); for (Annotation paramAnn : paramAnns) { // 解析@RequestParam註解 if (RequestParam.class.isInstance(paramAnn)) { RequestParam requestParam = (RequestParam) paramAnn; paramName = requestParam.name(); required = requestParam.required(); defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); annotationsFound++; } // 解析@RequestHeader註解 else if (RequestHeader.class.isInstance(paramAnn)) { RequestHeader requestHeader = (RequestHeader) paramAnn; headerName = requestHeader.name(); required = requestHeader.required(); defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); annotationsFound++; } // 解析@RequestBody註解 else if (RequestBody.class.isInstance(paramAnn)) { requestBodyFound = true; annotationsFound++; } // 解析@CookieValue註解 else if (CookieValue.class.isInstance(paramAnn)) { CookieValue cookieValue = (CookieValue) paramAnn; cookieName = cookieValue.name(); required = cookieValue.required(); defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); annotationsFound++; } // 解析@PathVariable註解 else if (PathVariable.class.isInstance(paramAnn)) { PathVariable pathVar = (PathVariable) paramAnn; pathVarName = pathVar.value(); annotationsFound++; } // 解析@ModelAttribute註解 else if (ModelAttribute.class.isInstance(paramAnn)) { ModelAttribute attr = (ModelAttribute) paramAnn; attrName = attr.value(); annotationsFound++; } // 解析@Value註解 else if (Value.class.isInstance(paramAnn)) { defaultValue = ((Value) paramAnn).value(); } else { // 解析@Validated註解 Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class); if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) { validate = true; Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn)); validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints}); } } } if (annotationsFound > 1) { throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + "do not specify more than one such annotation on the same parameter: " + handlerMethod); } if (annotationsFound == 0) { // 解析通常參數值 Object argValue = resolveCommonArgument(methodParam, webRequest); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else if (defaultValue != null) { args[i] = resolveDefaultValue(defaultValue); } else { Class<?> paramType = methodParam.getParameterType(); if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { if (!paramType.isAssignableFrom(implicitModel.getClass())) { throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " + "Model or Map but is not assignable from the actual model. You may need to switch " + "newer MVC infrastructure classes to use this argument."); } args[i] = implicitModel; } else if (SessionStatus.class.isAssignableFrom(paramType)) { args[i] = this.sessionStatus; } else if (HttpEntity.class.isAssignableFrom(paramType)) { // 解析HttpEntity請求-》 args[i] = resolveHttpEntityRequest(methodParam, webRequest); } else if (Errors.class.isAssignableFrom(paramType)) { throw new IllegalStateException("Errors/BindingResult argument declared " + "without preceding model attribute. Check your handler method signature!"); } else if (BeanUtils.isSimpleProperty(paramType)) { paramName = ""; } else { attrName = ""; } } } if (paramName != null) { // @RequestParam 解析 -》 args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); } else if (headerName != null) { // @RequestHandler解析-》 args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); } else if (requestBodyFound) { // @RequestBody解析 -》 args[i] = resolveRequestBody(methodParam, webRequest, handler); } else if (cookieName != null) { // @CookieValue 解析 -》 args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); } else if (pathVarName != null) { // @PathVariable 解析 -》 args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); } else if (attrName != null) { // @ModelAttribute 解析-》 WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); if (binder.getTarget() != null) { // 參數綁定-》 doBind(binder, webRequest, validate, validationHints, !assignBindingResult); } args[i] = binder.getTarget(); if (assignBindingResult) { args[i + 1] = binder.getBindingResult(); i++; } implicitModel.putAll(binder.getBindingResult().getModel()); } } return args; }
說到最後
本次源碼解析僅表明我的觀點,僅供參考。