SpringMVC运行流程详解

这里写图片描述
这里写图片描述

Spring工作流程描述
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。

Spring工作流程描述

为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?

详细见J2EE设计模式-前端控制模式

Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?

符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。

具体流程:
在SpringMVC中主要是围绕着DispatcherServlet来设计,可以把它当做指挥中心。这里先说明一下SpringMVC文档给出的执行流程,然后是我们稍微具体的执行流程,最后是流程大致的源码跟踪。关于很很很详细的源码解析,这里暂先不做。

DispatcherServlet是一个Servlet,我们知道在Servlet在处理一个请求的时候会交给service方法进行处理,这里也不例外,DispatcherServlet继承了FrameworkServlet,首先进入FrameworkServlet的service方法:

protected void service(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
    //请求方法  
    String method = request.getMethod();  
    //PATCH方法单独处理  
    if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {  
        processRequest(request, response);  
    }  
    else {//其他的请求类型的方法经由父类,也就是HttpServlet处理  
        super.service(request, response);  
    }  
} 

HttpServlet中会根据请求类型的不同分别调用doGet或者doPost等方法,FrameworkServlet中已经重写了这些方法,在这些方法中会调用processRequest进行处理,在processRequest中会调用doService方法,这个doService方法就是在DispatcherServlet中实现的。下面就看下DispatcherServlet中的doService方法的实现。

请求到达DispatcherServlet
doService方法:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  

    //给request中的属性做一份快照  
    Map<String, Object> attributesSnapshot = null;  
    if (WebUtils.isIncludeRequest(request)) {  
        logger.debug("Taking snapshot of request attributes before include");  
        attributesSnapshot = new HashMap<String, Object>();  
        Enumeration<?> attrNames = request.getAttributeNames();  
        while (attrNames.hasMoreElements()) {  
            String attrName = (String) attrNames.nextElement();  
            if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
                attributesSnapshot.put(attrName, request.getAttribute(attrName));  
            }  
        }  
    }  

    //如果我们没有配置类似本地化或者主题的处理器之类的  
    //SpringMVC会使用默认的值  
    //默认配置文件是DispatcherServlet.properties  
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  
    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()) {  
            return;  
        }  
        // Restore the original attribute snapshot, in case of an include.  
        if (attributesSnapshot != null) {  
            restoreAttributesAfterInclude(request, attributesSnapshot);  
        }  
    }  
}  

DispatcherServlet开始真正的处理,doDispatch方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    HttpServletRequest processedRequest = request;  
    HandlerExecutionChain mappedHandler = null;  
    boolean multipartRequestParsed = false;  
    //SpringMVC中异步请求的相关知识,暂先不解释  
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  

    try {  
        ModelAndView mv = null;  
        Exception dispatchException = null;  

        try {  
            //先检查是不是Multipart类型的,比如上传等  
            //如果是Multipart类型的,则转换为MultipartHttpServletRequest类型  
            processedRequest = checkMultipart(request);  
            multipartRequestParsed = processedRequest != request;  

            //获取当前请求的Handler  
            mappedHandler = getHandler(processedRequest, false);  
            if (mappedHandler == null || mappedHandler.getHandler() == null) {  
                noHandlerFound(processedRequest, response);  
                return;  
            }  

            //获取当前请求的Handler适配器  
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  

            // 对于header中last-modified的处理  
            String method = request.getMethod();  
            boolean isGet = "GET".equals(method);  
            if (isGet || "HEAD".equals(method)) {  
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
                    return;  
                }  
            }  
            //拦截器的preHandle方法进行处理  
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
                return;  
            }  

            try {  
                //真正调用Handler的地方  
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
            }  
            finally {  
                if (asyncManager.isConcurrentHandlingStarted()) {  
                    return;  
                }  
            }  
            //处理成默认视图名,就是添加前缀和后缀等  
            applyDefaultViewName(request, mv);  
            //拦截器postHandle方法进行处理  
            mappedHandler.applyPostHandle(processedRequest, response, mv);  
        }  
        catch (Exception ex) {  
            dispatchException = ex;  
        }  
        //处理最后的结果,渲染之类的都在这里  
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
    }  
    catch (Exception ex) {  
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
    }  
    catch (Error err) {  
        triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
    }  
    finally {  
        if (asyncManager.isConcurrentHandlingStarted()) {  
            // Instead of postHandle and afterCompletion  
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
            return;  
        }  
        // Clean up any resources used by a multipart request.  
        if (multipartRequestParsed) {  
            cleanupMultipart(processedRequest);  
        }  
    }  
}

查找请求对应的Handler对象

protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {  
    return getHandler(request);  
}  

继续往下看getHandler:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    //遍历所有的handlerMappings进行处理  
    //handlerMappings是在启动的时候预先注册好的  
    for (HandlerMapping hm : this.handlerMappings) {  
        HandlerExecutionChain handler = hm.getHandler(request);  
        if (handler != null) {  
            return handler;  
        }  
    }  
    return null;  
}  

继续往下看getHandler,在AbstractHandlerMapping类中:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    //根据request获取handler  
    Object handler = getHandlerInternal(request);  
    if (handler == null) {  
        //如果没有找到就使用默认的handler  
        handler = getDefaultHandler();  
    }  
    if (handler == null) {  
        return null;  
    }  
    //如果Handler是String,表明是一个bean名称  
    //需要超照对应bean  
    if (handler instanceof String) {  
        String handlerName = (String) handler;  
        handler = getApplicationContext().getBean(handlerName);  
    }  
    //封装Handler执行链  
    return getHandlerExecutionChain(handler, request);  
}  

根据requrst获取handler
首先看下根据requrst获取handler步骤getHandlerInternal方法,在AbstractHandlerMethodMapping中:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {  
    //获取request中的url,用来匹配handler  
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);  
    //根据路径寻找Handler  
    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);  
    //根据handlerMethod中的bean来实例化Handler并添加进HandlerMethod  
    return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;  
} 

看下根据路径寻找handler的方法lookupHandlerMethod:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {  
    List<Match> matches = new ArrayList<Match>();  
    //直接匹配  
    List<T> directPathMatches = this.urlMap.get(lookupPath);  
    //如果有匹配的,就添加进匹配列表中  
    if (directPathMatches != null) {  
        addMatchingMappings(directPathMatches, matches, request);  
    }  
    //还没有匹配的,就遍历所有的处理方法查找  
    if (matches.isEmpty()) {  
        // No choice but to go through all mappings  
        addMatchingMappings(this.handlerMethods.keySet(), matches, request);  
    }  
    //找到了匹配的  
    if (!matches.isEmpty()) {  
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));  
        Collections.sort(matches, comparator);  
        //排序之后,获取第一个  
        Match bestMatch = matches.get(0);  
        //如果有多个匹配的,会找到第二个最合适的进行比较一下  
        if (matches.size() > 1) {  
            Match secondBestMatch = matches.get(1);  
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {  
                Method m1 = bestMatch.handlerMethod.getMethod();  
                Method m2 = secondBestMatch.handlerMethod.getMethod();  
                throw new IllegalStateException(  
                        "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +  
                        m1 + ", " + m2 + "}");  
            }  
        }  
        //设置request参数  
        handleMatch(bestMatch.mapping, lookupPath, request);  
        //返回匹配的url的处理的方法  
        return bestMatch.handlerMethod;  
    }  
    else {//最后还没有找到,返回null  
        return handleNoMatch(handlerMethods.keySet(), lookupPath, request);  
    }  
}  

获取默认Handler
如果上面没有获取到Handler,就会获取默认的Handler。如果还获取不到就返回null。

处理String类型的Handler
如果上面处理完的Handler是String类型的,就会根据这个handlerName获取bean。

封装Handler执行链
上面获取完Handler,就开始封装执行链了,就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain:
Java代码

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
    //如果当前Handler不是执行链类型,就使用一个新的执行链实例封装起来  
    HandlerExecutionChain chain =  
        (handler instanceof HandlerExecutionChain) ?  
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);  
    //先获取适配类型的拦截器添加进去拦截器链  
    chain.addInterceptors(getAdaptedInterceptors());  
    //当前的url  
    String lookupPath = urlPathHelper.getLookupPathForRequest(request);  
    //遍历拦截器,找到跟当前url对应的,添加进执行链中去  
    for (MappedInterceptor mappedInterceptor : mappedInterceptors) {  
        if (mappedInterceptor.matches(lookupPath, pathMatcher)) {  
            chain.addInterceptor(mappedInterceptor.getInterceptor());  
        }  
    }  

    return chain;  
}  

获取对应请求的Handler适配器
getHandlerAdapter:
Java代码

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  
    //遍历所有的HandlerAdapter,找到和当前Handler匹配的就返回  
    //我们这里会匹配到RequestMappingHandlerAdapter  
    for (HandlerAdapter ha : this.handlerAdapters) {  
        if (ha.supports(handler)) {  
            return ha;  
        }  
    }  
}  

缓存的处理
也就是对last-modified的处理

执行拦截器的preHandle方法
就是遍历所有的我们定义的interceptor,执行preHandle方法

使用Handler适配器执行当前的Handler
ha.handle执行当前Handler,我们这里使用的是RequestMappingHandlerAdapter,首先会进入AbstractHandlerMethodAdapter的handle方法:
Java代码

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
        throws Exception {  
    return handleInternal(request, response, (HandlerMethod) handler);  
}  

handleInternal方法,在RequestMappingHandlerAdapter中
Java代码

protected final ModelAndView handleInternal(HttpServletRequest request,  
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  

    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {  
        // Always prevent caching in case of session attribute management.  
        checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);  
    }  
    else {  
        // Uses configured default cacheSeconds setting.  
        checkAndPrepare(request, response, true);  
    }  

    // Execute invokeHandlerMethod in synchronized block if required.  
    if (this.synchronizeOnSession) {  
        HttpSession session = request.getSession(false);  
        if (session != null) {  
            Object mutex = WebUtils.getSessionMutex(session);  
            synchronized (mutex) {  
                return invokeHandleMethod(request, response, handlerMethod);  
            }  
        }  
    }  
    //执行方法,封装ModelAndView  
    return invokeHandleMethod(request, response, handlerMethod);  
}  

组装默认视图名称
前缀和后缀名都加上

执行拦截器的postHandle方法
遍历intercepter的postHandle方法。

处理最后的结果,渲染之类的
processDispatchResult方法:
Java代码

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,  
        HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {  

    boolean errorView = false;  

    if (exception != null) {  
        if (exception instanceof ModelAndViewDefiningException) {  
            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 (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  
        // Concurrent handling started during a forward  
        return;  
    }  

    if (mappedHandler != null) {  
        mappedHandler.triggerAfterCompletion(request, response, null);  
    }  
}  

重点看下render方法,进行渲染:
Java代码

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {  
    //设置本地化  
    Locale locale = this.localeResolver.resolveLocale(request);  
    response.setLocale(locale);  

    View view;  
    if (mv.isReference()) {  
        //解析视图名,得到视图  
        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);  
    }  
    else {  
        // No need to lookup: the ModelAndView object contains the actual View object.  
        view = mv.getView();  
        if (view == null) {  
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +  
                    "View object in servlet with name '" + getServletName() + "'");  
        }  
    }  

    //委托给视图进行渲染  
    view.render(mv.getModelInternal(), request, response);  
} 

view.render就是进行视图的渲染,然后跳转页面等处理。

到这里大概的流程就走完了。其中涉及到的东西还有很多,暂先不做详细处理。

猜你喜欢

转载自blog.csdn.net/qq_38070608/article/details/80514792
今日推荐