1

SpringMVC总结

一、spring MVC的工作内容

  1. 将URL映射到Java类或者方法

  2. 封装用户提交的数据

  3. 处理请求,调用相关的业务层,并封装响应的数据

  4. 将要响应的数据进行渲染

二、SpringMVC的优点和特点

  1. 与spring无缝集成(IOC、AOP)

  2. 约定优于配置

  3. 性能比Struts2好

  4. 设计中的角色或者职责划分明确

  5. Restful

  6. JUnit测试

  7. 异常处理

  8. 本地化、国际化

  9. 数据验证、类型转化等

  10. 拦截器

  11. 使用的人和公司比较多

  12. 简单、便捷、易学

springMVC处理请求的流程

springMVC基于请求驱动,所有设计都围绕一个中央servlet展开,它负责将请求分发给各个处理器(页面控制器、Controller),下图展示了springMVC处理请求的流程,图中的Front Controller(前端控制器)正是springMVC的DispatcherServlet;Controller称为处理器或应用控制器,由它来处理具体的请求,返回数据模型;View Template为具体视图,用于展示数据,响应请求.
图片描述

具体处理请求步骤:

  1. 用户发送请求,被前端拦截器拦截,前端控制器根据请求的信息选择相应的页面控制器,并将请求委托给此页面控制器来处理。

  2. 页面控制器接收到请求后,首先收集并绑定请求参数到一个命令对象(表单对象)中,并进行验证转换等操作,然后将命令对象委托给业务对象处理,最后返回一个modelAndView对象。

  3. 前端控制器根据返回的视图名,选择相应的视图进行渲染,并将模型数据传入到视图中以便展示。

  4. 前端控制器将响应的结果返回给用户。

至此,整个请求流程结束,当然还有一些细节的问题,需要我们了解,比如:前端控制器如何选择页面控制器,前端控制器如果根据页面控制器的返回选择相应的视图进行渲染,等等。带着这些问题,我们将springMVC处理请求的流程图转换为架构图讨论一下。

图片描述

先上一段代码:

 /**
     * Process the actual dispatching to the handler.
     * <p>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.
     * <p>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
     */
    /**
     * 处理实际的请求分发到处理器.
     * 要获得具体的Handler, 需要先使用servlet的HandlerMappings.
     * 要获得HandlerAdpter, 需要先在servlet加载的各HandlerAdapter中查找, 找到第一个支持此Handler的Adapter.
     * 所有的HTTP方法都通过这个方法来处理的. 这个方法中, 由HandlerAdapter或Handler自己来决定哪些方法可以被调用.
     * @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(文件上传)
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                // 图中2,3两步, 通过HandlerMappsing映射, 获取处理请求的Handler
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                // 图中步骤4, 将Handler包装成Adapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                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.
                // 图中5,6,7步骤, 由HandlerAdapter调用真正的处理器处理请求, 并返回ModelAndView对象
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(processedRequest, mv);

                // 后置拦截器
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            // 图中8,9,10,11步骤, 处理Handler的处理结果, 这个结果可能是一个ModelAndView对象, 还可能是一个异常
            // 第8,9步, 由viewResolver解析视图
            // viewResolver.resolveViewName(viewName, locale)
            // 第10, 11步, 传入Model, 并渲染视图
            // view.render(mv.getModelInternal(), request, response);
            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
                if (mappedHandler != null) {
                    // 完成时拦截器
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }
  1. 步骤①, DispatcherServlet作为前端控制器, 统一的请求接收点, 控制全局的请求流程. 接收到用户请求, 自己不做处理, 而是将请求委托给其他的处理器进行处理.

  2. 步骤②③, DispatcherServlet通过HandlerMapping(处理映射器), 将请求映射为一个HandlerExecutionChain对象, 其中包括了页面控制器和对其配置的拦截器.

  3. 步骤④, DispatcherServlet通过获得的Handler(处理器, 页面控制器, Controller), 查找一个合适的HandlerAdapter(处理器适配器), 通过这个HandlerAdapter调用Handler实际处理请求的方法.

  4. 步骤⑤, 提取请求中的模型数据, 调用Handler实际处理请求的方法. 在调用方法时, 填充参数过程中, spring会根据配置做一些工作, 如: 数据转换, 数据格式化, 数据验证等.

  5. 步骤⑥⑦, Handler执行完成后, 将返回一个ModelAndView对象给DispatherServlet. ModelAndView对象中包含逻辑视图名或逻辑视图名和模型.

  6. 步骤⑧, 根据ModelAndView对象选择一个合适的ViewResolver(视图解析器).

  7. 步骤⑨, ViewResolver将ModelAndView中的逻辑视图名解释成View对象. ViewResolver也是接口, 同样采用了策略模式, 这样就很容易切换其他的视图类型.

  8. 步骤⑩⑪, 渲染视图时, 将Model数据传入视图中, 这里的Model数据是一个Map, 容易与各种视图类型相结合.

  9. 步骤⑫, 最后, 由DispatcherServlet将最终的响应结果返回给用户.

通过这些步骤, springmvc依赖几个对象共同完成了请求到响应的工作流程, 对于开发者来说, 这些对象是不可见的, 开发者只需要关心Handler处理器(页面控制器)中对请求的处理业务即可.

staunch
50 声望2 粉丝