SpringMVC源码分析(二)

来源:互联网 发布:阿里云服务器硬盘扩容 编辑:程序博客网 时间:2024/05/16 13:41

  上一篇博文SpringMVC源码分析(一) 中已经对SpringMVC中的Servlet(GenericServlet,HttpServlet,HttpServletBean,FrameworkServlet,DispatcherServlet)源码进行分析,今天接着分析SpringMVC请求处理过程。

  SpringMVC请求处理过程主要由DispatchServlet来负责完成,FrameworkServlet是DispatchServlet的父类,先看一下FrameWorkServlet的处理请求过程。
  
  当接收到请求时会调用service方法,代码如下:

    @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);//如果请求方式是PATCH时直接调用        }        else {            super.service(request, response);//调用父类的service方法,也就是HttpServlet的service方法        }    }

  service方法中会根据请求类型选择处理方式,比如get请求就会调用doGet()方法,
FrameworkServlet中重写doGet()方法,代码如下:

@Override    protected final void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        processRequest(request, response);    }

  所以最后会调用processRequest处理请求,processRequest是FrameworkServlet类处理请求的核心方法。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        long startTime = System.currentTimeMillis();        Throwable failureCause = null;        //获取LocalContextHolder中保存LocalContext(保存了本地化信息,比如zh-cn)        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();        //获取当前请求的LocalContext(保存了本地化信息,比如zh-cn)        LocaleContext localeContext = buildLocaleContext(request);        //获取RequestContextHolder保存的RequestAttributes        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();        //获取当前请求的RequestAttributes        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());        //将当前的LocalContext和RequestAttributes分别放置到LocalContextHolder和RequestContextHolder中        initContextHolders(request, localeContext, requestAttributes);        try {            //实际处理请求的入口            doService(request, response);//在DispatchServlet中实现        }        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 {            //恢复原来的LocalContext和ServletRequestAttributes到LocalContextHolder和RequestContextHolder中            resetContextHolders(request, previousLocaleContext, previousAttributes);            if (requestAttributes != null) {                requestAttributes.requestCompleted();//执行完这个方法后isRequestActive()返回值为false            }            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");                    }                }            }            //发送servletRequestHandlerEvent消息            publishRequestHandledEvent(request, response, startTime, failureCause);        }    }

  ServletRequestAttributes中封装了我们平时使用setAttribute和getAttribute方法,根据scope参数来判断是request还是session。

    @Override    public void setAttribute(String name, Object value, int scope) {        if (scope == SCOPE_REQUEST) {            if (!isRequestActive()) {//上面调用了requestCompleted之后就会变为false也就是不进行操作了                throw new IllegalStateException(                        "Cannot set request attribute - request is not active anymore!");            }            this.request.setAttribute(name, value);        }        else {            HttpSession session = getSession(true);            this.sessionAttributesToUpdate.remove(name);            session.setAttribute(name, value);        }    }

  publishRequestHandledEvent方法是请求处理结束后会发出消息,无论请求是否成功都会发出。

  接下来继续看service()处理请求,service方法会调用doService方法,doService是个模板方法,DispatcherServlet中重写了这个方法,我们转到ServletDispatcherServlet上分析处理请求过程,DispatcherServlet是Spring 的最核心的类。整个处理请求的过程的顶层设计都在这里。我们来看看DispatcherServlet的doService方法。

@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<String, Object> attributesSnapshot = null;        //当include请求时把request中的atrribute备份一份        if (WebUtils.isIncludeRequest(request)) {            attributesSnapshot = new HashMap<String, Object>();            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.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());//设置webApplication        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);//设置localResolver        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);//设置themeResolver        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());//设置themeResource        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);//用于redirect中attribute的数据传递        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) {                    //还原request中的attribute                    restoreAttributesAfterInclude(request, attributesSnapshot);                }            }        }    }

  继续追踪doDispatch方法,doDispatch主要的任务是根据request找到Handler,根据handler找到相对应的HandlerAdapter,用HandlerAdapter处理Handler,最后把结果通过processDispatchResult()返回,实现代码如下:

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);                // Determine handler for the current request.                mappedHandler = getHandler(processedRequest);//通过请求找到handler(这里的handler就是我们说的Controller中处理请求的方法)                if (mappedHandler == null || mappedHandler.getHandler() == null) {                    noHandlerFound(processedRequest, response);//没有找到handler则调用此方法处理                    return;                }                // Determine handler adapter for the current request.                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//通过handler找到HandlerAdapter                // Process last-modified header, if supported by the handler.                String method = request.getMethod();//获取请求方式                boolean isGet = "GET".equals(method);                if (isGet || "HEAD".equals(method)) {                    //处理GET、HEAD请求的Last-Modified                    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;                    }                }                //执行相应Interceptor的preHandler方法                if (!mappedHandler.applyPreHandle(processedRequest, response)) {                    return;                }                //handlerAdapter使用handler处理请求                // Actually invoke the handler.                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                if (asyncManager.isConcurrentHandlingStarted()) {                    return;                }                //当View为空时,比如我们写的Controller中处理请求的方法为空时,根据request的设置view                applyDefaultViewName(processedRequest, mv);                //执行相应Intercerptor的postHandler方法                mappedHandler.applyPostHandle(processedRequest, response, mv);            }            catch (Exception ex) {                dispatchException = ex;            }            catch (Throwable err) {                dispatchException = new NestedServletException("Handler dispatch failed", err);            }            //返回处理结果,包括异常处理、渲染页面、发出通知出发Interceptor的afterCompletion方法            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);                }            }        }    }

可以看出doDispatch方法中的核心工作就是
  1.根据当前Request找到handler;
  2.根据Handler找到对应的HandlerAdapter;
  3.使用HandlerAdapter处理handler
  4.调用processDispatchResult方法处理上面请求之后的结果

补充几个重要的概念:
  Handler:也就是处理器,他直接对应着MVC的Controller层,他的表现形式很多,标注了@RequestMapping的所有方法都可以看出一个handler,只要能处理实际请求的就可以是Handler。
  HandlerMapping:用来查找Handler的,SpringMVC的请求很多,每个请求都需要一个handler来处理,收到的请求由那个handler来处理就由HandlerMapping来确定。
  HandlerAdapter:他就是一个适配器,SpringMVC中handler的形式可以任意,主要能处理请求就OK,但是Servlet处理请求的方法结构是固定的。如何让固定的servlet处理方法调用灵活的handler来处理就由HandlerAdapter来实现。

  接着分析handlerAdpter中调用handler方法处理请求。

public interface HandlerAdapter {    //判断是否可以用某个handler    boolean supports(Object handler);    //具体使用Handler处理请求    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;    //返回LastModified的值    long getLastModified(HttpServletRequest request, Object handler);}

我们只要实现HandlerAdapter接口就可以处理请求,SimpleControllerHandlerAdapter实现了HandlerAdapter,实现代码如下:

public class SimpleControllerHandlerAdapter implements HandlerAdapter {    //判断是否可以用某个handler    @Override    public boolean supports(Object handler) {        return (handler instanceof Controller);    }    @Override    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)            throws Exception {        //调用Controller接口中的handleRequest方法,我们如果继承了Controller接口就需要重写这个方法,然后在里面处理逻辑即可。        return ((Controller) handler).handleRequest(request, response);    }    @Override    public long getLastModified(HttpServletRequest request, Object handler) {        if (handler instanceof LastModified) {            return ((LastModified) handler).getLastModified(request);        }        return -1L;    }}

  请求处理完的结果会封装在ModelAndView中,我们通过processDispatchResult方法把结果渲染到页面中,实现代码如下:

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) {                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;        }        //发出请求处理完成的通知,出发Interceptor的afterCompletion        if (mappedHandler != null) {            mappedHandler.triggerAfterCompletion(request, response, null);        }    }

  在render方法中会去查找视图解析器,然后转化成View类型的视图(比如jsp,html,freemaker等)显示在页面上。

阅读全文
0 0
原创粉丝点击