文档章节

Spring MVC - 请求处理

i
 itititit
发布于 2017/08/25 13:44
字数 878
阅读 28
收藏 0

HttpServletBean

主要参与创建工作,没有涉及请求的处理。

 

 

FrameworkServlet

将所有的请求合并到了processRequest()。

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
//获取原来保存的LocalContext,以便后面恢复
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//取得当前请求的LocaleContext
        LocaleContext localeContext = this.buildLocaleContext(request);
//获取原来保存的RequestAttributes,以便后面恢复
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//获取当前请求的LocaleContext
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
//设置到静态抽象类的ThreadLocal中
        this.initContextHolders(request, localeContext, requestAttributes);

        try {
//模板方法,DispatcherServlet实现
            this.doService(request, response);
        } catch (ServletException var17) {
            failureCause = var17;
            throw var17;
        } catch (IOException var18) {
            failureCause = var18;
            throw var18;
        } catch (Throwable var19) {
            failureCause = var19;
            throw new NestedServletException("Request processing failed", var19);
        } finally {
//恢复上述内容
            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
            if(requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            if(this.logger.isDebugEnabled()) {
                if(failureCause != null) {
                    this.logger.debug("Could not complete request", (Throwable)failureCause);
                } else if(asyncManager.isConcurrentHandlingStarted()) {
                    this.logger.debug("Leaving response open for concurrent processing");
                } else {
                    this.logger.debug("Successfully completed request");
                }
            }

            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }

    }

this.initContextHolders(request, localeContext, requestAttributes); 将LocaleContext和RequestAttributes设置到静态抽象类的ThreadLocal属性中,可通过LocaleContext.getLocaleContext()在service层获得Locale信息,RequestAttributes同理。可以通过getRequest、getSession、getResponse,在任何地方都能方便的取得

最后发布消息,可通过实现ApplicationListener<ServletRequestHandleEvent>,并在类上标注@Component就可以了。

 

 

DispatcherServlet

请求处理入口是doService()。

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if(this.logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":"";
            this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }

        Map<String, Object> attributesSnapshot = null;
//如果是include请求,则对request的attribute做快照
        if(WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();

            label108:
            while(true) {
                String attrName;
                do {
                    if(!attrNames.hasMoreElements()) {
                        break label108;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
//设置request属性
//前四个属性在handler和view中使用。
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
//后三个属性与flashMap有关。redirect传递flashMap传递参数。
        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 {
            this.doDispatch(request, response);
        } finally {
//还原上述快照
            if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

        }

    }

redirect时可通过向handler的方法中传入RedirectAttributes类型的参数,把需要的属性设置到里面

而后有交给了doDispatcher()。

 

 

doDispatcher()

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

                try {
//检查是不是上传请求
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
//通过request找到handler
                    mappedHandler = this.getHandler(processedRequest);
                    if(mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

//通过handler找到handlerAdapter
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
//处理GET、HEAD请求的Last-Modified
                    boolean isGet = "GET".equals(method);
                    if(isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if(this.logger.isDebugEnabled()) {
                            this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }

                        if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
//执行相应Interceptor的preHandle()
                    if(!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
//通handlerAdapter处理handler
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//如果需要异步,直接返回
                    if(asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
//View返回空时,根据request设置默认View
                    this.applyDefaultViewName(processedRequest, mv);
//执行Interceptor的postHandle()
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var19) {
                    dispatchException = var19;
                }
//处理上面的结果。包括异常处理、渲染页面、触发Interceptor的afterCompletion
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            } catch (Exception var20) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
            } catch (Error var21) {
                this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
            }

        } finally {
            if(asyncManager.isConcurrentHandlingStarted()) {
                if(mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if(multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
  • Handler:具体处理请求的处理器,对应Controller层,表现形式有很多种,可以是类,也可以是方法,类型是Object,标注了@RequestMapping的都可以看作handler。
  • HandlerMapping:用来查找Handler。
  • HandlerAdapter:Handler可以是任意形式的,而Servlet需要处理的方法结构是固定的。adapter让固定的Servlet调用灵活的Handler。

View和ViewResolver的原理与Handler和HandlerMapping类似。View用于展示数据,ViewResolver用来查找View,Model是View要展示的数据。

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

i
粉丝 0
博文 24
码字总数 15531
作品 0
私信 提问
Spring MVC原理及配置详解

【spring】Spring MVC原理及配置 1.Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架。借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简...

qq58edf1d989a2d
2018/06/26
0
0
spring MVC 静态资源处理

对于spring mvc的静态资源处理。 由于初期的时候对于spring MVC对于静态资源的处理并不是很好,如果将DispatcherServlet请求映射配置为"/",则springMVC则将捕获web容器所有请求,包括静态资...

bosscheng
2013/05/07
801
0
Spring MVC 执行过程详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/Rsx/article/details/96309840 文章目录 Spring MVC简述 大部分Java应...

不专业得Cook
07/17
0
0
仿照源码,手写一个自定义 Spring MVC 框架

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/GitChat/article/details/97947618 前言 上节课我们学习了 Spring M...

GitChat技术杂谈
07/31
0
0
SpringMVC基础知识 (1)

1. Spring体系结构  如图所示,MyBatis属于其管理下的ORM(持久层映射)层,而SpringMVC则属于Web-MVC处理层的框架。 Spring MVC有以下优点: Spring MVC技术是与Spring框架结合而成的,它同...

LeaveStyle
2018/08/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Qt qml 自定义消息提示框

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/a844651990/article/details/78376767 Qt qml 自定义消息提...

shzwork
昨天
5
0
Linux安装JDK

(rpm) ⒈下载:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ⒉安装 rpm -ivh jdk-8u202-linux-x64.rpm ⒊配置环境变量 vim /etc/profile 添加......

无名氏的程序员
昨天
2
0
The POM for xxx is invalid, transitive dependencies (if any) will not be available

The POM for xxx is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details 问题描述 在使用maven打包时,log信息中打印出:[**WARNIN......

lwenhao
昨天
6
0
setState() called after dispose() flutter

# 在setState前加入以下判断if (!mounted) return;

zdglf
昨天
4
0
docker和docker-compose二种方式安装mysql8.0

Docker方式安装 在命令行下运行 docker run -d -p 3306:3306 --restart always --privileged=true--name mysql-e MYSQL_USER="test" -e MYSQL_PASSWORD="test" -e MYSQL_ROOT_PASSWOR......

小白的成长
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部