博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC请求处理过程浅析
阅读量:4224 次
发布时间:2019-05-26

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

这里写图片描述

上图完整描绘了SpringMVC的请求处理过程,可以看到,此过程都是以DispatcherServlet为中轴线进行的,而具体的处理逻辑在DispatcherServlet的doDispatch方法中,

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {        HttpServletRequest processedRequest = request;        HandlerExecutionChain mappedHandler = null;        boolean multipartRequestParsed = false;        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);        try {            ModelAndView mv = null;            Exception dispatchException = null;            try {                processedRequest = checkMultipart(request);                multipartRequestParsed = (processedRequest != request);                mappedHandler = getHandler(processedRequest);                ……                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                ……                if (!mappedHandler.applyPreHandle(processedRequest, response)) {                    return;                }                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                if (asyncManager.isConcurrentHandlingStarted()) {                    return;                }                applyDefaultViewName(processedRequest, mv);                mappedHandler.applyPostHandle(processedRequest, response, mv);            }            ……            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);        }        ……    }

1,调用getHandler方法,根据请求request信息寻找对应的Handler,调用链如下:

DispatcherServlet.getHandler()        -->AbstractHandlerMapping.getHandler()            -->AbstractUrlHandlerMapping.getHandlerInternal()                -->AbstractUrlHandlerMapping.getHandlerExecutionChain()

以SimpleUrlHandlerMapping为例分析,顾名思义,此步骤的步骤就是根据请求URL找到匹配的Controller,并通过getgetHandlerExecutionChain方法对返回的Handler进行封装,以保证满足返回类型的匹配。先看一下getHandlerInternal方法,

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);        //根据请求路径寻找handler        Object handler = lookupHandler(lookupPath, request);        if (handler == null) {            Object rawHandler = null;            if ("/".equals(lookupPath)) {                rawHandler = getRootHandler();            }            if (rawHandler == null) {                rawHandler = getDefaultHandler();            }            if (rawHandler != null) {                // Bean name or resolved handler?                if (rawHandler instanceof String) {                    String handlerName = (String) rawHandler;                    rawHandler = obtainApplicationContext().getBean(handlerName);                }                validateHandler(rawHandler, request);                //将Handler封装成HandlerExecutionChain类型                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);            }        }        ……        return handler;    }

lookupHandler整个过程虽然比较复杂,但不难理解,考虑了直接匹配与通配符两种情况,再看一下将Handler封装成HandlerExecutionChain的过程。

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)) {                    chain.addInterceptor(mappedInterceptor.getInterceptor());                }            }            else {                chain.addInterceptor(interceptor);            }        }        return chain;    }

通过将Handler以参数形式传入,并构建HandlerExecutionChain类型实例,并加入事先配置的拦截器。

2,根据当前Handler寻找对应的HandlerAdapter

笔者曾经很疑惑,既然handler都有了,直接调用处理方法不就可以了,为什么又多出来一个HandrAdapter。其实这正是适配器模式的体现,通过URL匹配的Handler类型千变万化,通过加入适配器,将不同类型Handler的调用过程统一化,体现了面向对象编程中的开闭原则——对扩展开发、对修改关闭。

默认情况下,SpringMVC支持HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、AnnotationMethodHandlerAdapter三种适配器。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {        if (this.handlerAdapters != null) {            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");    }

3,HandlerInterceptor处理

SpringMVC允许通过处理拦截Web请求,进行前置处理和后置处理,需要注意的是,一般情情况下,两者的处理顺序相反。

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];                if (!interceptor.preHandle(request, response, this.handler)) {                    triggerAfterCompletion(request, response, null);                    return false;                }                this.interceptorIndex = i;            }        }        return true;    }    /**     * Apply postHandle methods of registered interceptors.     */    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable 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);            }        }    }

4,逻辑处理

逻辑处理其实是通过适配器中转调用Handler并返回视图,对应代码:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

5,后处理

对于上述逻辑处理结果的处理,也许有异常,也许有正常ModelAndView对象返回,都在processDispatchResult方法中,其中包含了两个步骤:1,异常视图的处理;2,解析视图并跳转页面。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,            @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,            @Nullable Exception exception) throws Exception {        boolean errorView = false;        if (exception != null) {            if (exception instanceof ModelAndViewDefiningException) {                logger.debug("ModelAndViewDefiningException encountered", exception);                mv = ((ModelAndViewDefiningException) exception).getModelAndView();            }            else {                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);                mv = processHandlerException(request, response, handler, exception);                errorView = (mv != null);            }        }        // Did the handler return a view to render?        if (mv != null && !mv.wasCleared()) {            render(mv, request, response);            if (errorView) {                WebUtils.clearErrorRequestAttributes(request);            }        }        else {            if (logger.isDebugEnabled()) {                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +                        "': assuming HandlerAdapter completed request handling");            }        }        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {            // Concurrent handling started during a forward            return;        }        if (mappedHandler != null) {            mappedHandler.triggerAfterCompletion(request, response, null);        }    }

以上是SpringMVC处理请求的大致过程,笔者忽略了一些异常处理场景,重点关注核心流程,希望对读者有所帮助。

你可能感兴趣的文章
独家 | 使用高斯混合模型,让聚类更好更精确(附数据&代码&学习资源)
查看>>
研究学者、医师与产业投资者齐聚一堂,将碰撞出何种火花?
查看>>
报名丨西山金融科技产业创新论坛邀您参会
查看>>
知识图谱从哪里来:实体关系抽取的现状与未来
查看>>
数据蒋堂 | 大清单报表的打印?
查看>>
近期活动盘点:高级机器学习训练营、基于神经网络的代码自动生成” “开放学术图谱”、西山金融科技产业创新论坛...
查看>>
独家 | 一文盘点AutoML 库(附PPT等链接)
查看>>
独家|图说Pandas中旋转和重塑函数
查看>>
独家 | 一文读懂概率论学习:贝叶斯理论(附链接)
查看>>
报名 | 统计学概论和医疗临床大数据分析讲座
查看>>
102页PPT,DeepMind强化学习最新进展,含图文、公式和代码
查看>>
清华自然语言处理科学家孙茂松:深度学习碰壁之后,我们还能做什么?
查看>>
独家 | 19年NAACL纪实:自然语言处理的实用性见解
查看>>
独家 | 数据科学家应该避免的5种统计陷阱(附链接)
查看>>
干货 | 22道机器学习常见面试题目
查看>>
干货 | 统计学概论和医疗临床大数据分析(附PPT下载)
查看>>
《2019人工智能发展报告》!含计算机视觉、机器人等13个子领域(附链接)
查看>>
奖学金申请 | 2019年清华-青岛数据科学研究院“RONG”奖学金申请通知
查看>>
数据蒋堂 | BI系统中容易被忽视的数据源功能
查看>>
原始数据哪里找?这些网站要用好!200个国内外经济/金融/行研/咨询数据网站大全(附链接)...
查看>>