MultipartContent类型的request处理
对于请求的处理,Spring首先考虑的是对于Multipart的处理,如果是MultipartContent类型的request,则转换为MultipartHttpServletRequest类型的Request。
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) { if (request.getDispatcherType().equals(DispatcherType.REQUEST)) { logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter"); } } else if (hasMultipartException(request) ) { logger.debug("Multipart resolution previously failed for current request - " + "skipping re-resolution for undisturbed error rendering"); } else { try { return this.multipartResolver.resolveMultipart(request); } catch (MultipartException ex) { if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) { logger.debug("Multipart resolution failed for error dispatch", ex); // Keep processing error dispatch with regular request handle below } else { throw ex; } } } } // If not returned before: return original request. return request; }
根据request信息寻找对应的Handler
在Spring加载的过程中,Spring会将类型为SimpleUrlHandlerMapping的实例加载到this.HandlerMappings中,按照常理推断,根据request提取对应的Handler,但是该Handler继承自AbstractController类型实例,与HandlerExecutionChain并无任何关联,那么这一步是如何封装的呢?
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
在系统启动的时候Spring会将所有的映射类型的bean注册到this.handlerMappings变量中,所以此函数的目的就是遍历所有的HandlerMapping,并调用其getHandler方法进行封装处理。以SimpleURLHandlerMapping为例查看其getHandler方法如下:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //根据request获取对应的handler Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { //如果没有对应request的handler则使用默认的handler return null; } // 如果也没有提供默认的handler则无法继续处理返回null if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (logger.isTraceEnabled()) { logger.trace("Mapped to " + handler); } else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) { logger.debug("Mapped to " + executionChain.getHandler()); } if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
上述函数首先使用getHandlerInternal方法根据request信息获取对应的Handler,如果以SimpleUrlHandlerMapping为例分析,那么我们推断此步骤提供的功能很可能就是根据URL找到匹配的Controller并返回,当然如果没有找到对应的Controller处理器那么程序会尝试去查找配置中的默认处理器,当然,当查找的Controller为String类型时,那就意味着返回的是配置的bean名称,需要根据bean名称查找对应的bean,最后,还要通过getHandlerExecutionChain方法返回的Handler进行封装,以保证满足返回类型的匹配。下面详细分析这个过程:
1.根据request查找对应的Handler
首先从根据request查找对应的Handler开始分析:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { //截取用于匹配的URL有效路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //根据路径寻找Handler Object handler = lookupHandler(lookupPath, request); if (handler == null) { Object rawHandler = null; if ("/".equals(lookupPath)) { //如果请求的路径仅仅是“/",那么使用RootHandler进行处理 rawHandler = getRootHandler(); } if (rawHandler == null) { //无法找到Handler则使用默认的Handler rawHandler = getDefaultHandler(); } if (rawHandler != null) { // 根据beanName获取对应的bean if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = obtainApplicationContext().getBean(handlerName); } //模板方法 validateHandler(rawHandler, request); handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } return handler; }
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // Pattern match? List<String> matchingPatterns = new ArrayList<>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) { matchingPatterns.add(registeredPattern +"/"); } } } String bestMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); //直接匹配的情况处理 if (!matchingPatterns.isEmpty()) { matchingPatterns.sort(patternComparator); if (logger.isTraceEnabled() && matchingPatterns.size() > 1) { logger.trace("Matching patterns " + matchingPatterns); } 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 + "]"); } } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them Map<String, String> uriTemplateVariables = new LinkedHashMap<>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestMatch, matchingPattern) == 0) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) { logger.trace("URI variables " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }