码迷,mamicode.com
首页 > 编程语言 > 详细

spring MVC mybatis dispacherServlet(源码解读)

时间:2016-12-15 21:07:50      阅读:429      评论:0      收藏:0      [点我收藏+]

标签:equal   ann   容器   路径   after   jar包   bean   前端   分段上传   

dispacherServlet是servlet的实现类,是spring MVC的前端转发器,是spring MVC的核心。

那么它做了哪些事呢?

它主要做了两件事:

NO1:

看如下源码:

/**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
protected void initStrategies(ApplicationContext context) {  
          //初始化分段上传解析器(成对文件上传的解析和封装工作),没有默认的实现    
          initMultipartResolver(context);  
          //初始化地域解析器,默认实现是AcceptHeaderLocaleResolver  
          initLocaleResolver(context);  
           //初始化主题解析器,默认实现是FixedThemeResolver  
          initThemeResolver(context);  
           //初始化处理器映射,这是个集合, 默认实现是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping   
          initHandlerMappings(context);  
           //初始化处理器适配器,这是个集合,默认实现是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter    
          initHandlerAdapters(context);  
            //初始化处理器异常解析器,这是个集合,默认实现是AnnotationMethodHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver   
          initHandlerExceptionResolvers(context);  
          //初始化请求到视图名解析器,默认实现是DefaultRequestToViewNameTranslator    
          initRequestToViewNameTranslator(context);  
          //初始化视图解析器,这是个集合,默认实现是InternalResourceViewResolver    
          initViewResolvers(context);  
     }  

NO2:

每次请求都会调用它的doService方法,在doService方法中调用它的doDispatch方法。

doService方法可看代码中的两处注释:

技术分享

 重点在于调用它的doDispatch方法:

doDispatch(request, response);

 

 首先我们来看方法doDispatch的注释:

技术分享

可以简单理解成:所有的请求都将在这个方法里映射到指定的handler的指定的方法(前提:请求路径正确)。

我们来一步一步解析这个方法:

以下,为

doDispatch方法的源码:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// processedRequest是经过checkMultipart方法处理过的request请求
        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);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                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.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

                applyDefaultViewName(processedRequest, mv);
                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
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

 

 

 第一行新建的变量processedRequest 会在

 后面某一行(在doDispatch方法中,如下:)

processedRequest = checkMultipart(request);

 

 中被方法处理加工,checkMultipart方法也是dispacherServlet类中的一个方法,源码如下:

技术分享

 那么这个方法的作用是什么呢?

关键是下面这一句:

this.multipartResolver != null && this.multipartResolver.isMultipart(request)

 

 这一句代码做了如下两个判断:

1.dispacherServlet中初始化后的multipartResolver是否为空(配置文件中是否配置,初始化dispacherServlet时没有默认实例);

2.multipartResolver的方法isMultipart的作用是判断本次请求是否为文件上传。

如下为isMultipart的源码:

技术分享

通过注释,可简单理解为:该方法通常以检查content-type是否为multipart/form-data的方式判断本次请求是否为文件上传,但实际功能需要看具体解析器对该方法的实现细节。

checkMultipart方法大致如此,再具体一些的内容在这里我就不赘述了,有兴趣的朋友可以自己看源码。

 (多嘴一句:若想使用multipartResolver不要忘了增加jar包支持:commons.fileupload,common.io).

---------------------------------------

方法doDispatch的第二行新建了变量mappedHandler ,

类型为HandlerExecutionChain ,通过查看该类的源码,可清楚请作用,如下:

技术分享

可理解其为一个处理链,包含了所有的handler和拦截器。

 以下两行代码为doDispatch的核心:

// Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);

 

 

// Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

 

 通过注释,可理解前一句的作用:映射到指定的handler,

后一句:映射到指定的handler中具体的一个方法(handler adapter)。

以下是我debug断点的显示数据:

技术分享

该方法时DispatcherServlet类中的方法getHandler,可以看到这里会对所有handlerMapper进行遍历,后执行HandlerMappering的getHandler方法,

如下:为HandlerMappering的getHandler方法:

技术分享

这个方法会返回一个handler和所有的拦截器,组装成了一个HandlerExecutionChain类。也就是在方法doDispatch第二行代码里定义的mappedHandler,

该方法的具体实现是在org.springframework.web.servlet.handler.AbstractHandlerMapping中,如下:

    /**
     * Look up a handler for the given request, falling back to the default
     * handler if no specific one is found.
     * @param request current HTTP request
     * @return the corresponding handler instance, or the default handler
     * @see #getHandlerInternal
     */
    @Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }

        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }

 

这里的getHandlerInternal是个抽象方法,有具体的HandlerMapping来实现,获取到的handler如果为空,则获取默认配置的handler,若为string类型,则表示要去spring配置容器中去找这个bean。

 

 

未结束。

 

spring MVC mybatis dispacherServlet(源码解读)

标签:equal   ann   容器   路径   after   jar包   bean   前端   分段上传   

原文地址:http://www.cnblogs.com/zqsky/p/6184436.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!