博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单读!spring-mvc源码之穿越http请求
阅读量:7229 次
发布时间:2019-06-29

本文共 84080 字,大约阅读时间需要 280 分钟。

  相信spring-mvc这种被玩坏了的架构理念,大家都烂熟于胸了,不过还是想来扒一扒他的细节。

  一个http请求,怎么样被 spring 接收,又怎样做出响应呢?

一般地,我们会配置一个 web.xml,然后开始代码之旅。

   在 web.xml 中配置 servlet-mapping, 将请求转发到 DispatcherServlet, 那么我们认为 DispatcherServlet 是我们的第一棒交接者!

springMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:applicationContext.xml
1
springMVC
/

// tomcat 接到http请求后,会主动创建一个servlet, 然后调用进应用代码中, 创建的代码如下

// Allocate a servlet instance to process this request        try {            if (!unavailable) {                servlet = wrapper.allocate();            }        } catch (ServletException e) {            wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",                             wrapper.getName()), StandardWrapper.getRootCause(e));            servletException = e;        } catch (Throwable e) {            ExceptionUtils.handleThrowable(e);            wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",                             wrapper.getName()), e);            servletException = new ServletException                (sm.getString("applicationDispatcher.allocateException",                              wrapper.getName()), e);            servlet = null;        }

// org.apache.catalina.core.StandardWrapper.allocate(), 创建 servlet,

/**     * Allocate an initialized instance of this Servlet that is ready to have     * its service() method called.  If the servlet class does     * not implement SingleThreadModel, the (only) initialized     * instance may be returned immediately.  If the servlet class implements     * SingleThreadModel, the Wrapper implementation must ensure     * that this instance is not allocated again until it is deallocated by a     * call to deallocate().     *     * @exception ServletException if the servlet init() method threw     *  an exception     * @exception ServletException if a loading error occurs     */    @Override    public Servlet allocate() throws ServletException {        // If we are currently unloading this servlet, throw an exception        if (unloading) {            throw new ServletException(sm.getString("standardWrapper.unloading", getName()));        }        boolean newInstance = false;        // If not SingleThreadedModel, return the same instance every time        if (!singleThreadModel) {            // Load and initialize our instance if necessary            if (instance == null || !instanceInitialized) {                synchronized (this) {                    if (instance == null) {                        try {                            if (log.isDebugEnabled()) {                                log.debug("Allocating non-STM instance");                            }                            // Note: We don't know if the Servlet implements                            // SingleThreadModel until we have loaded it.                            instance = loadServlet();                            newInstance = true;                            if (!singleThreadModel) {                                // For non-STM, increment here to prevent a race                                // condition with unload. Bug 43683, test case                                // #3                                countAllocated.incrementAndGet();                            }                        } catch (ServletException e) {                            throw e;                        } catch (Throwable e) {                            ExceptionUtils.handleThrowable(e);                            throw new ServletException(sm.getString("standardWrapper.allocate"), e);                        }                    }                    if (!instanceInitialized) {                        initServlet(instance);                    }                }            }            if (singleThreadModel) {                if (newInstance) {                    // Have to do this outside of the sync above to prevent a                    // possible deadlock                    synchronized (instancePool) {                        instancePool.push(instance);                        nInstances++;                    }                }            } else {                if (log.isTraceEnabled()) {                    log.trace("  Returning non-STM instance");                }                // For new instances, count will have been incremented at the                // time of creation                if (!newInstance) {                    countAllocated.incrementAndGet();                }                return instance;            }        }        synchronized (instancePool) {            while (countAllocated.get() >= nInstances) {                // Allocate a new instance if possible, or else wait                if (nInstances < maxInstances) {                    try {                        instancePool.push(loadServlet());                        nInstances++;                    } catch (ServletException e) {                        throw e;                    } catch (Throwable e) {                        ExceptionUtils.handleThrowable(e);                        throw new ServletException(sm.getString("standardWrapper.allocate"), e);                    }                } else {                    try {                        instancePool.wait();                    } catch (InterruptedException e) {                        // Ignore                    }                }            }            if (log.isTraceEnabled()) {                log.trace("  Returning allocated STM instance");            }            countAllocated.incrementAndGet();            return instancePool.pop();        }    }
View Code

 

// 最后,会先调用 filter, 完成之后再调用 servlet.service()

private void internalDoFilter(ServletRequest request,                                  ServletResponse response)        throws IOException, ServletException {        // Call the next filter if there is one        if (pos < n) {            ApplicationFilterConfig filterConfig = filters[pos++];            try {                Filter filter = filterConfig.getFilter();                if (request.isAsyncSupported() && "false".equalsIgnoreCase(                        filterConfig.getFilterDef().getAsyncSupported())) {                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);                }                if( Globals.IS_SECURITY_ENABLED ) {                    final ServletRequest req = request;                    final ServletResponse res = response;                    Principal principal =                        ((HttpServletRequest) req).getUserPrincipal();                    Object[] args = new Object[]{req, res, this};                    SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);                } else {                    filter.doFilter(request, response, this);                }            } catch (IOException | ServletException | RuntimeException e) {                throw e;            } catch (Throwable e) {                e = ExceptionUtils.unwrapInvocationTargetException(e);                ExceptionUtils.handleThrowable(e);                throw new ServletException(sm.getString("filterChain.filter"), e);            }            return;        }        // We fell off the end of the chain -- call the servlet instance        try {            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {                lastServicedRequest.set(request);                lastServicedResponse.set(response);            }            if (request.isAsyncSupported() && !servletSupportsAsync) {                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,                        Boolean.FALSE);            }            // Use potentially wrapped request from this point            if ((request instanceof HttpServletRequest) &&                    (response instanceof HttpServletResponse) &&                    Globals.IS_SECURITY_ENABLED ) {                final ServletRequest req = request;                final ServletResponse res = response;                Principal principal =                    ((HttpServletRequest) req).getUserPrincipal();                Object[] args = new Object[]{req, res};                SecurityUtil.doAsPrivilege("service",                                           servlet,                                           classTypeUsedInService,                                           args,                                           principal);            } else {                servlet.service(request, response);            }        } catch (IOException | ServletException | RuntimeException e) {            throw e;        } catch (Throwable e) {            e = ExceptionUtils.unwrapInvocationTargetException(e);            ExceptionUtils.handleThrowable(e);            throw new ServletException(sm.getString("filterChain.servlet"), e);        } finally {            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {                lastServicedRequest.set(null);                lastServicedResponse.set(null);            }        }    }

 

// 现在,到了 DispatcherServlet 出场了,由 DispatcherServlet 的父类 org.springframework.web.servlet.FrameworkServlet.service()接力, 开始处理

/**     * Override the parent class implementation in order to intercept PATCH requests.     */    @Override    protected void service(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());        if (HttpMethod.PATCH == httpMethod || httpMethod == null) {            processRequest(request, response);        }        else {            // 交由 HttpServlet.service() 处理,转发 doGet,doPost 等等方法            super.service(request, response);        }    }        // 父类 HttpServlet.service(), 只负责转发请求,由子类进行相应处理    protected void service(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException    {        String method = req.getMethod();        if (method.equals(METHOD_GET)) {            long lastModified = getLastModified(req);            if (lastModified == -1) {                // servlet doesn't support if-modified-since, no reason                // to go through further expensive logic                doGet(req, resp);            } else {                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);                if (ifModifiedSince < lastModified) {                    // If the servlet mod time is later, call doGet()                    // Round down to the nearest second for a proper compare                    // A ifModifiedSince of -1 will always be less                    maybeSetLastModified(resp, lastModified);                    doGet(req, resp);                } else {                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);                }            }        } else if (method.equals(METHOD_HEAD)) {            long lastModified = getLastModified(req);            maybeSetLastModified(resp, lastModified);            doHead(req, resp);        } else if (method.equals(METHOD_POST)) {            doPost(req, resp);                    } else if (method.equals(METHOD_PUT)) {            doPut(req, resp);                    } else if (method.equals(METHOD_DELETE)) {            doDelete(req, resp);                    } else if (method.equals(METHOD_OPTIONS)) {            doOptions(req,resp);                    } else if (method.equals(METHOD_TRACE)) {            doTrace(req,resp);                    } else {            //            // Note that this means NO servlet supports whatever            // method was requested, anywhere on this server.            //            String errMsg = lStrings.getString("http.method_not_implemented");            Object[] errArgs = new Object[1];            errArgs[0] = method;            errMsg = MessageFormat.format(errMsg, errArgs);                        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);        }    }

 

// 比如 FrameworkServlet.doGet()/doXXX() 方法重写, 调用 processRequest()

/**     * Delegate GET requests to processRequest/doService.     * 

Will also be invoked by HttpServlet's default implementation of {

@code doHead}, * with a {
@code NoBodyResponse} that just captures the content length. * @see #doService * @see #doHead */ @Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }

View Code

 

// FrameworkServlet.processRequest() 做一些全局设置,然后交由 doService() 进行具体处理, doService() 由子类实现,也即 DispatcherServlet.doService()

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        long startTime = System.currentTimeMillis();        Throwable failureCause = null;        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();        LocaleContext localeContext = buildLocaleContext(request);        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());        initContextHolders(request, localeContext, requestAttributes);        try {            // 具体处理,交由 DispatcherServlet 处理            doService(request, response);        }        catch (ServletException ex) {            failureCause = ex;            throw ex;        }        catch (IOException ex) {            failureCause = ex;            throw ex;        }        catch (Throwable ex) {            failureCause = ex;            throw new NestedServletException("Request processing failed", ex);        }        finally {            resetContextHolders(request, previousLocaleContext, previousAttributes);            if (requestAttributes != null) {                // 请求完成回调                requestAttributes.requestCompleted();            }            if (logger.isDebugEnabled()) {                if (failureCause != null) {                    this.logger.debug("Could not complete request", failureCause);                }                else {                    if (asyncManager.isConcurrentHandlingStarted()) {                        logger.debug("Leaving response open for concurrent processing");                    }                    else {                        this.logger.debug("Successfully completed request");                    }                }            }            // 发布完成事件            publishRequestHandledEvent(request, response, startTime, failureCause);        }    }

 

// locale 上下文管理

private void initContextHolders(            HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {        //     private static final ThreadLocal
localeContextHolder = new NamedThreadLocal
("LocaleContext"); if (localeContext != null) { LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable); } // private static final ThreadLocal
requestAttributesHolder = new NamedThreadLocal
("Request attributes"); if (requestAttributes != null) { RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); } if (logger.isTraceEnabled()) { logger.trace("Bound request context to thread: " + request); } }

 

// org.springframework.web.servlet.DispatcherServlet, 进行具体请求转发

/**     * Exposes the DispatcherServlet-specific request attributes and delegates to {
@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map
attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap
(); Enumeration
attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. // 设备各种处理器到 request 中 // 上下文管理 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); // locale 管理 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); // themeResolver request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }

 

// doDispatch(), 实际分发方法

/**     * Process the actual dispatching to the handler.     * 

The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. *

All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ 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 { // 封装 multipart 文件上传,如果是文件上传类,则将其封装为 MultipartHttpServletRequest, 以便后续直接使用 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 获取具体uri业务处理器,即 由 RequestMapping 设置的路径 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { // 如果没有找到 handler 则结束处理 noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 对GET|HEAD 进行 last-modified 进行检测 String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 进行处理器前置调用,如果未通过,则结束 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. // 调用业务处理 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 设置 view applyDefaultViewName(processedRequest, mv); // 后置处理 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 最后再处理一次结果,如果有必要的话 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { // 清理环境 if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }

 

// multipart 检测,需设置 multipartResolver, 方能转换,否则直接返回原始请求

/**     * Convert the request into a multipart request, and make multipart resolver available.     * 

If no multipart resolver is set, simply use the existing request. * @param request current HTTP request * @return the processed request (multipart wrapper if necessary) * @see MultipartResolver#resolveMultipart */ protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml"); } else if (hasMultipartException(request) ) { logger.debug("Multipart resolution failed for current request before - " + "skipping re-resolution for undisturbed error rendering"); } else { try { // 调用 multipartResolver.resolveMultipart(), 由 resolver 进行文件转换处理 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; }

View Code

// 关键: 获取handler, 以待调用

/**     * Return the HandlerExecutionChain for this request.     * 

Tries all handler mappings in order. * @param request current HTTP request * @return the HandlerExecutionChain, or {

@code null} if no handler could be found */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // handlerMappings 中保存了所有可用的路由 for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } // 由具体的 HandlerMapping 去解析自己的映射 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping // org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler() /** * Look up a handler for the given request, falling back to the default * handler if no specific one is found. * @param request current HTTP request * @return the corresponding handler instance, or the default handler * @see #getHandlerInternal */ @Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 获取 handlerMethod Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } // 获取 handler 链 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(), 查找 handler /** * Look up a handler method for the given request. */ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // UrlHelper.getLookupPathForRequest() 进行路径分析 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } // 加锁读取 this.mappingRegistry.acquireReadLock(); try { // 根据path查找 handlerMethod 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 + "]"); } } // 找到匹配后,将 handler 通过 bean 查找方式包装进 HandlerMethod 中返回 return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }

 

// 更细节的查询 handler 动作

// org.springframework.web.util.UrlPathHelper    /**     * Return the mapping lookup path for the given request, within the current     * servlet mapping if applicable, else within the web application.     * 

Detects include request URL if called within a RequestDispatcher include. * @param request current HTTP request * @return the lookup path * @see #getPathWithinApplication * @see #getPathWithinServletMapping */ public String getLookupPathForRequest(HttpServletRequest request) { // Always use full path within current servlet context? if (this.alwaysUseFullPath) { return getPathWithinApplication(request); } // Else, use path within current servlet mapping if applicable String rest = getPathWithinServletMapping(request); if (!"".equals(rest)) { return rest; } else { // 返回 /hello/test return getPathWithinApplication(request); } } // /** * Return the path within the servlet mapping for the given request, * i.e. the part of the request's URL beyond the part that called the servlet, * or "" if the whole URL has been used to identify the servlet. *

Detects include request URL if called within a RequestDispatcher include. *

E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a". *

E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a". *

E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a". *

E.g.: servlet mapping = "/test"; request URI = "/test" -> "". *

E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "". * @param request current HTTP request * @return the path within the servlet mapping, or "" */ public String getPathWithinServletMapping(HttpServletRequest request) { String pathWithinApp = getPathWithinApplication(request); String servletPath = getServletPath(request); String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp); String path; // If the app container sanitized the servletPath, check against the sanitized version if (servletPath.contains(sanitizedPathWithinApp)) { path = getRemainingPath(sanitizedPathWithinApp, servletPath, false); } else { path = getRemainingPath(pathWithinApp, servletPath, false); } if (path != null) { // Normal case: URI contains servlet path. return path; } else { // Special case: URI is different from servlet path. String pathInfo = request.getPathInfo(); if (pathInfo != null) { // Use path info if available. Indicates index page within a servlet mapping? // e.g. with index page: URI="/", servletPath="/index.html" return pathInfo; } if (!this.urlDecode) { // No path info... (not mapped by prefix, nor by extension, nor "/*") // For the default servlet mapping (i.e. "/"), urlDecode=false can // cause issues since getServletPath() returns a decoded path. // If decoding pathWithinApp yields a match just use pathWithinApp. path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false); if (path != null) { return pathWithinApp; } } // Otherwise, use the full servlet path. return servletPath; } }// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping /** * 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 { List
matches = new ArrayList
(); List
directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { // 添加到匹配中,考虑不止一个匹配 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { // 如果有多个匹配,进行优先级排序,判断是否可用,然后取第一个作为最终的 handler Comparator
comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } Match bestMatch = matches.get(0); if (matches.size() > 1) { if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } 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 + "}"); } } // 解析参数到 handlerMethod 中 handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } } // AbstractHandlerMethodMapping$MappingRegistry.getMappingsByUrl() /** * Return matches for the given URL path. Not thread-safe. * @see #acquireReadLock() */ public List
getMappingsByUrl(String urlPath) { // private final MultiValueMap
urlLookup = new LinkedMultiValueMap
(); // 内部使用 Map
> targetMap; 进行保存关系映射 return this.urlLookup.get(urlPath); } // AbstractHandlerMethodMapping, 将确实有效的mapping添加到 matches 中 private void addMatchingMappings(Collection
mappings, List
matches, HttpServletRequest request) { for (T mapping : mappings) { // 重新严格校验路径,参数,header, 返回新的mapping T match = getMatchingMapping(mapping, request); if (match != null) { // 将 handler 放入 match // private class Match {} matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }

View Code

 

// org.springframework.web.servlet.mvc.condition.HeadersRequestCondition
// org.springframework.web.servlet.mvc.method.RequestMappingInfo
// 进行参数校验,并封装返回参数信息到 RequestMappingInfo 中返回

/**     * 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.     * 

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 = this.methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); // 其中某个不匹配,则返回 null if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); }

 

/**     * Expose URI template variables, matrix variables, and producible media types in the request.     * @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE     * @see HandlerMapping#MATRIX_VARIABLES_ATTRIBUTE     * @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE     */    @Override    protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {        super.handleMatch(info, lookupPath, request);        String bestPattern;        Map
uriVariables; Map
decodedUriVariables; Set
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
> matrixVars = extractMatrixVariables(request, uriVariables); request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars); } if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) { Set
mediaTypes = info.getProducesCondition().getProducibleMediaTypes(); request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes); } }
View Code

 

// org.springframework.web.method.HandlerMethod.createWithResolvedBean(), 重新包装一个带bean实例的 HandlerMethod

/**     * 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; // spring beans 组件 handler = this.beanFactory.getBean(beanName); } return new HandlerMethod(this, handler); }

 

/**     * Build a {
@link HandlerExecutionChain} for the given handler, including * applicable interceptors. *

The default implementation builds a standard {

@link HandlerExecutionChain} * with the given handler, the handler mapping's common interceptors, and any * {
@link MappedInterceptor}s matching to the current request URL. Interceptors * are added in the order they were registered. Subclasses may override this * in order to extend/rearrange the list of interceptors. *

NOTE: The passed-in handler object may be a raw handler or a * pre-built {

@link HandlerExecutionChain}. This method should handle those * two cases explicitly, either building a new {
@link HandlerExecutionChain} * or extending the existing chain. *

For simply adding an interceptor in a custom subclass, consider calling * {

@code super.getHandlerExecutionChain(handler, request)} and invoking * {
@link HandlerExecutionChain#addInterceptor} on the returned chain object. * @param handler the resolved handler instance (never {
@code null}) * @param request current HTTP request * @return the HandlerExecutionChain (never {
@code null}) * @see #getAdaptedInterceptors() */ protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 取出内层的 interceptor 使用 chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }

 

// 获取 adapter,适配不同类型的调用

// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter// org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter// org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter    /**     * Return the HandlerAdapter for this handler object.     * @param handler the handler object to find an adapter for     * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.     */    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");    }

 

// mappedHandler.applyPreHandle(processedRequest, response) , 前置调用处理, interceptor 拦截调用

/**     * Apply preHandle methods of registered interceptors.     * @return {
@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; // 接收 preHandle 返回值, false 则终止 if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }

 

// mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 真正调用 handler 处理业务
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
// method.AbstractHandlerMethodAdapter

/**     * 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); } // @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; // 预检查是否可支持 checkRequest(request); // 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) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No synchronization on session demanded at all... // invoke mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; }

 

//org.springframework.web.servlet.support.WebContentGenerator.checkRequest()    /**     * Check the given request for supported methods and a required session, if any.     * @param request current HTTP request     * @throws ServletException if the request cannot be handled because a check failed     * @since 4.2     */    protected final void checkRequest(HttpServletRequest request) throws ServletException {        // Check whether we should support the request method.        String method = request.getMethod();        if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {            throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);        }        // Check whether a session is required.        if (this.requireSession && request.getSession(false) == null) {            throw new HttpSessionRequiredException("Pre-existing session required but none found");        }    }
View Code

 

// 调用 Adapter 的 handler 处理方法

/**     * Invoke the {
@link RequestMapping} handler method preparing a {
@link ModelAndView} * if view resolution is required. * @since 4.2 * @see #createInvocableHandlerMethod(HandlerMethod) */ 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); // createInvocableHandlerMethod, 反射调用工具类 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // mav 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(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } // 调用业务 controller invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 返回 mv, jsp, 如果是 json 一类的输出,则直接返回 null return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }

细节点的工厂类创建:

// 参数绑定工厂    private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {        Class
handlerType = handlerMethod.getBeanType(); Set
methods = this.initBinderCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); this.initBinderCache.put(handlerType, methods); } List
initBinderMethods = new ArrayList
(); // Global methods first for (Entry
> entry : this.initBinderAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { Object bean = entry.getKey().resolveBean(); for (Method method : entry.getValue()) { initBinderMethods.add(createInitBinderMethod(bean, method)); } } } for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(createInitBinderMethod(bean, method)); } return createDataBinderFactory(initBinderMethods); } // 参数解析工厂 private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod); Class
handlerType = handlerMethod.getBeanType(); Set
methods = this.modelAttributeCache.get(handlerType); if (methods == null) { methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); this.modelAttributeCache.put(handlerType, methods); } List
attrMethods = new ArrayList
(); // Global methods first for (Entry
> entry : this.modelAttributeAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { Object bean = entry.getKey().resolveBean(); for (Method method : entry.getValue()) { 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); }
View Code

 

// org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle()

/**     * Invoke the method and handle the return value through one of the     * configured {
@link HandlerMethodReturnValueHandler}s. * @param webRequest the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type (not resolved) */ public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 直接调用 handler Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 设置响应码 setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { 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; } } // InvocableHandlerMethod.invokeForRequest() /** * Invoke the method after resolving its argument values in the context of the given request. *

Argument values are commonly resolved through {

@link HandlerMethodArgumentResolver}s. * The {
@code providedArgs} 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 if the method raised an exception */ public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取方法参数 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) + "' with arguments " + Arrays.toString(args)); } // invoke Object returnValue = doInvoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) + "] returned [" + returnValue + "]"); } return returnValue; }

 

// 参数封装,InvocableHandlerMethod.getMethodArgumentValues()

// InvocableHandlerMethod.getMethodArgumentValues()    /**     * 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);            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.isDebugEnabled()) {                        logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);                    }                    throw ex;                }            }            if (args[i] == null) {                throw new IllegalStateException("Could not resolve method parameter at index " +                        parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +                        ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));            }        }        return args;    }    // org.springframework.web.method.support.HandlerMethodArgumentResolverComposite    /**     * Iterate over registered {
@link HandlerMethodArgumentResolver}s and invoke the one that supports it. * @throws IllegalStateException if no suitable {
@link HandlerMethodArgumentResolver} is found. */ @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }// AbstractNamedValueMethodArgumentResolver @Override public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); // 处理 key Object resolvedName = resolveStringValue(namedValueInfo.name); if (resolvedName == null) { throw new IllegalArgumentException( "Specified name must not resolve to null: [" + namedValueInfo.name + "]"); } // 获取 value Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { arg = resolveStringValue(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 = resolveStringValue(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()); } } handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; }
View Code

 

// Object returnValue = doInvoke(args); 

// InvocableHandlerMethod.doInvoke(), 正常返回结果,异常包装返回

/**     * Invoke the handler method with the given argument values.     */    protected Object doInvoke(Object... args) throws Exception {        // 确保方法可调用        ReflectionUtils.makeAccessible(getBridgedMethod());        try {            // 调用业务方法            return getBridgedMethod().invoke(getBean(), args);        }        catch (IllegalArgumentException ex) {            assertTargetBean(getBridgedMethod(), getBean(), args);            String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");            throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);        }        catch (InvocationTargetException ex) {            // Unwrap for HandlerExceptionResolvers ...            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 {                String text = getInvocationErrorMessage("Failed to invoke handler method", args);                throw new IllegalStateException(text, targetException);            }        }    }

// 至此业务方法终于调用完成

// 接下来,处理返回值

// this.returnValueHandlers.handleReturnValue(//                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);// org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue()    /**     * Iterate over registered {
@link HandlerMethodReturnValueHandler}s and invoke the one that supports it. * @throws IllegalStateException if no suitable {
@link HandlerMethodReturnValueHandler} is found. */ @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }// 返回值处理器// org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler// org.springframework.web.method.annotation.ModelMethodProcessor// org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor// org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler// org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler// org.springframework.web.method.annotation.ModelAttributeMethodProcessor// org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor// org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler// org.springframework.web.method.annotation.MapMethodProcessor// org.springframework.web.method.annotation.ModelAttributeMethodProcessor private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } // return Callable.class.isAssignableFrom(returnType.getParameterType()); // return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || // returnType.hasMethodAnnotation(ResponseBody.class)); if (handler.supportsReturnType(returnType)) { return handler; } } return null; } // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(), 处理返回结果 @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // 写返回值 // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); } /** * Creates a new {
@link HttpOutputMessage} from the given {
@link NativeWebRequest}. * @param webRequest the web request to create an output message from * @return the output message */ protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) { HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); return new ServletServerHttpResponse(response); } /** * Writes the given return type to the given output message. * @param value the value to write to the output message * @param returnType the type of the value * @param inputMessage the input messages. Used to inspect the {
@code Accept} header. * @param outputMessage the output message to write to * @throws IOException thrown in case of I/O errors * @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated * by the {
@code Accept} header on the request cannot be met by the message converters */ @SuppressWarnings("unchecked") protected
void writeWithMessageConverters(T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object outputValue; Class
valueType; Type declaredType; if (value instanceof CharSequence) { // string 的返回值输出 outputValue = value.toString(); valueType = String.class; declaredType = String.class; } else { outputValue = value; valueType = getReturnValueType(outputValue, returnType); declaredType = getGenericType(returnType); } HttpServletRequest request = inputMessage.getServletRequest(); // 获取返回的 content-type 值 List
requestedMediaTypes = getAcceptableMediaTypes(request); List
producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType); if (outputValue != null && producibleMediaTypes.isEmpty()) { throw new IllegalArgumentException("No converter found for return value of type: " + valueType); } Set
compatibleMediaTypes = new LinkedHashSet
(); for (MediaType requestedType : requestedMediaTypes) { for (MediaType producibleType : producibleMediaTypes) { if (requestedType.isCompatibleWith(producibleType)) { compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType)); } } } if (compatibleMediaTypes.isEmpty()) { if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return; } List
mediaTypes = new ArrayList
(compatibleMediaTypes); MediaType.sortBySpecificityAndQuality(mediaTypes); // 确定输出的类型 MediaType selectedMediaType = null; for (MediaType mediaType : mediaTypes) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break; } else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break; } } if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); // 使用 messageConverter 进行返回值转换 // org.springframework.http.converter.ByteArrayHttpMessageConverter // org.springframework.http.converter.StringHttpMessageConverter // org.springframework.http.converter.ResourceHttpMessageConverter // org.springframework.http.converter.xml.SourceHttpMessageConverter // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter // org.springframework.http.converter.ByteArrayHttpMessageConverter // org.springframework.http.converter.StringHttpMessageConverter // org.springframework.http.converter.ResourceHttpMessageConverter // org.springframework.http.converter.xml.SourceHttpMessageConverter // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter for (HttpMessageConverter
messageConverter : this.messageConverters) { if (messageConverter instanceof GenericHttpMessageConverter) { if (((GenericHttpMessageConverter) messageConverter).canWrite( declaredType, valueType, selectedMediaType)) { outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class
>) messageConverter.getClass(), inputMessage, outputMessage); if (outputValue != null) { addContentDispositionHeader(inputMessage, outputMessage); ((GenericHttpMessageConverter) messageConverter).write( outputValue, declaredType, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } } return; } } else if (messageConverter.canWrite(valueType, selectedMediaType)) { // 输出值 outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class
>) messageConverter.getClass(), inputMessage, outputMessage); if (outputValue != null) { addContentDispositionHeader(inputMessage, outputMessage); // write ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType + "\" using [" + messageConverter + "]"); } } return; } } } if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); } }

 

// 消息转换器

// org.springframework.http.converter.StringHttpMessageConverter

// org.springframework.http.converter.AbstractHttpMessageConverter

// org.springframework.http.converter.StringHttpMessageConverter// org.springframework.http.converter.AbstractHttpMessageConverter    /**     * This implementation sets the default headers by calling {
@link #addDefaultHeaders}, * and then calls {
@link #writeInternal}. */ @Override public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { final HttpHeaders headers = outputMessage.getHeaders(); addDefaultHeaders(headers, t, contentType); if (outputMessage instanceof StreamingHttpOutputMessage) { StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage; streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() { @Override public void writeTo(final OutputStream outputStream) throws IOException { writeInternal(t, new HttpOutputMessage() { @Override public OutputStream getBody() throws IOException { return outputStream; } @Override public HttpHeaders getHeaders() { return headers; } }); } }); } else { // write writeInternal(t, outputMessage); // 再次 flush() outputMessage.getBody().flush(); } } // StringHttpMessageConverter @Override protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException { if (this.writeAcceptCharset) { outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets()); } Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType()); StreamUtils.copy(str, charset, outputMessage.getBody()); } // org.springframework.util.StreamUtils.copy() // 像socket中写入返回值,即向浏览器一类请求客户端输出返回值,到此,客户端得到响应 /** * Copy the contents of the given String to the given output OutputStream. * Leaves the stream open when done. * @param in the String to copy from * @param charset the Charset * @param out the OutputStream to copy to * @throws IOException in case of I/O errors */ public static void copy(String in, Charset charset, OutputStream out) throws IOException { Assert.notNull(in, "No input String specified"); Assert.notNull(charset, "No charset specified"); Assert.notNull(out, "No OutputStream specified"); Writer writer = new OutputStreamWriter(out, charset); writer.write(in); writer.flush(); }

 

// return getModelAndView(mavContainer, modelFactory, webRequest);
// RequestMappingHandlerAdapter

// return getModelAndView(mavContainer, modelFactory, webRequest);// RequestMappingHandlerAdapter    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,            ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {        // 如果已经处理完成,返回null        modelFactory.updateModel(webRequest, mavContainer);        if (mavContainer.isRequestHandled()) {            return null;        }        // 否则处理 mv        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
flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }

 

// prepareResponse(response);
// RequestMappingHandlerAdapter

/**     * Prepare the given response according to the settings of this generator.     * Applies the number of cache seconds specified for this generator.     * @param response current HTTP response     * @since 4.2     */    protected final void prepareResponse(HttpServletResponse response) {        if (this.cacheControl != null) {            applyCacheControl(response, this.cacheControl);        }        else {            applyCacheSeconds(response, this.cacheSeconds);        }        if (servlet3Present && this.varyByRequestHeaders != null) {            for (String value : getVaryRequestHeadersToAdd(response)) {                response.addHeader("Vary", value);            }        }    }
View Code

 

// mappedHandler.applyPostHandle(processedRequest, response, mv);
// org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()

// org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()    /**     * Apply postHandle methods of registered interceptors.     */    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {        HandlerInterceptor[] interceptors = getInterceptors();        if (!ObjectUtils.isEmpty(interceptors)) {            for (int i = interceptors.length - 1; i >= 0; i--) {                HandlerInterceptor interceptor = interceptors[i];                interceptor.postHandle(request, response, this.handler, mv);            }        }    }

 

// processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

/**     * Handle the result of handler selection and handler invocation, which is     * either a ModelAndView or an Exception to be resolved to a ModelAndView.     */    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {        boolean errorView = false;        // 发生异常,使用 errorView        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(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) {            // 最后再一个触发器钩子,触发 interceptor.afterCompletion()            mappedHandler.triggerAfterCompletion(request, response, null);        }    }        /**     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.     * Will just invoke afterCompletion for all interceptors whose preHandle invocation     * has successfully completed and returned true.     */    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)            throws Exception {        HandlerInterceptor[] interceptors = getInterceptors();        if (!ObjectUtils.isEmpty(interceptors)) {            for (int i = this.interceptorIndex; i >= 0; i--) {                HandlerInterceptor interceptor = interceptors[i];                try {                    interceptor.afterCompletion(request, response, this.handler, ex);                }                catch (Throwable ex2) {                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);                }            }        }    }

 

// 依次返回 doDispatch(),清理环境
// 返回 FrameworkServlet.doService()
// FrameworkServlet finally中还会触发 requestAttributes.requestCompleted();

// org.springframework.web.context.request.ServletRequestAttributes.requestCompleted()    /**     * Signal that the request has been completed.     * 

Executes all request destruction callbacks and updates the * session attributes that have been accessed during request processing. */ public void requestCompleted() { executeRequestDestructionCallbacks(); updateAccessedSessionAttributes(); this.requestActive = false; } /** * Execute all callbacks that have been registered for execution * after request completion. */ private void executeRequestDestructionCallbacks() { synchronized (this.requestDestructionCallbacks) { for (Runnable runnable : this.requestDestructionCallbacks.values()) { // 同步调用 DestructionCallbacks.run() runnable.run(); } this.requestDestructionCallbacks.clear(); } } /** * Update all accessed session attributes through {

@code session.setAttribute} * calls, explicitly indicating to the container that they might have been modified. */ @Override protected void updateAccessedSessionAttributes() { if (!this.sessionAttributesToUpdate.isEmpty()) { // Update all affected session attributes. HttpSession session = getSession(false); if (session != null) { try { for (Map.Entry
entry : this.sessionAttributesToUpdate.entrySet()) { String name = entry.getKey(); Object newValue = entry.getValue(); Object oldValue = session.getAttribute(name); if (oldValue == newValue && !isImmutableSessionAttribute(name, newValue)) { session.setAttribute(name, newValue); } } } catch (IllegalStateException ex) { // Session invalidated - shouldn't usually happen. } } this.sessionAttributesToUpdate.clear(); } }// 最后 publishRequestHandledEvent(request, response, startTime, failureCause);// FrameworkServlet private void publishRequestHandledEvent( HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) { if (this.publishEvents) { // Whether or not we succeeded, publish an event. long processingTime = System.currentTimeMillis() - startTime; int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1); // 发布 event 到 spring, 使感兴趣的监听者进行相应处理 this.webApplicationContext.publishEvent( new ServletRequestHandledEvent(this, request.getRequestURI(), request.getRemoteAddr(), request.getMethod(), getServletConfig().getServletName(), WebUtils.getSessionId(request), getUsernameForRequest(request), processingTime, failureCause, statusCode)); } }

 

       总结几个技术要点:

           1. filterchain 责任链模式的使用;

           2. 工厂模式的使用;

           3. 拦截器监听;

           4. 各功能组件化,职责分明;

           5. 模板方法模式使用;

           6. mvc;

           7. 适配器模式应用;

           8. 观察者模式应用;

转载地址:http://spdfm.baihongyu.com/

你可能感兴趣的文章
Debian – 出现-bash: pip: command not found错误解决办法
查看>>
Zxing扫描二维码
查看>>
我的友情链接
查看>>
aspcms后台拿shell漏洞(非添加模块)及修复方法
查看>>
C语言冒泡排序法
查看>>
B2B行业门户网站群发邮件时间及发送频率
查看>>
关于虚拟机能ping通物理机,而物理机ping不通虚拟机问题解决。
查看>>
同台机器启动多个mysql
查看>>
iframe 跨域高度自适应
查看>>
struts2+hibernate3+spring3(ssh2)框架下的web应用
查看>>
Linux下的三个时间属性
查看>>
semanage
查看>>
[case分享]Exchange 2010 登陆OWA查看邮件出现Rights managem operation failed
查看>>
linux dd 读取 写入磁盘速度
查看>>
dmidecode查看linux硬件信息
查看>>
linux监控对象及重要性
查看>>
walle-web自动化部署配置
查看>>
opencv轮廓提取、轮廓识别相关要点
查看>>
BOOST.ASIO源码剖析(一)
查看>>
过滤squidlog中各个链接的大小
查看>>