美文网首页
详解DispatcherServlet

详解DispatcherServlet

作者: winyiwin | 来源:发表于2017-10-17 23:36 被阅读0次

    DispatcherServlet调用点方法

    // 上层的调用方法为AbstractApplicationContext#refresh()---》onRefresh();
     @Override
        protected void onRefresh(ApplicationContext context) {
            initStrategies(context);
        }
    
        /**
         * 初始化解析器、映射器,适配器等等,根据/org/springframework/web/servlet/DispatcherServlet.properties 配置文件初始化
         */
        protected void initStrategies(ApplicationContext context) {
            initMultipartResolver(context);
            initLocaleResolver(context);
            initThemeResolver(context);
            initHandlerMappings(context);
            initHandlerAdapters(context);
            initHandlerExceptionResolvers(context);
            initRequestToViewNameTranslator(context);
            initViewResolvers(context);
            initFlashMapManager(context);
        }
    

    最主要的处理方法

    doDispatch(HttpServletRequest request, HttpServletResponse response)

    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);
    
                // 1.为当前的请求匹配对应的处理Handler,其实也就是根据url去匹配要执行Controller哪个方法.详见 解释1
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                //2.确定当前请求的适配器
                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;
                    }
                }
    // 3 前置通知器 HandlerInterceptor
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
    
                // 4.实际执行
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
    
                applyDefaultViewName(processedRequest, mv);
        //5. 后置过滤拦截
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
    //6.视图渲染、返回值处理
            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);
                }
            }
        }
    }
    
    1. 解释1
      getHandler()-->AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest request)。把HandlerMapping封装成HandlerExecutionChain
    @Override
        protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
            String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
            if (logger.isDebugEnabled()) {
                logger.debug("Looking up handler method for path " + lookupPath);
            }
            this.mappingRegistry.acquireReadLock();
            try {
                HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
                if (logger.isDebugEnabled()) {
                    if (handlerMethod != null) {
                        logger.debug("Returning handler method [" + handlerMethod + "]");
                    }
                    else {
                        logger.debug("Did not find handler method for [" + lookupPath + "]");
                    }
                }
                return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
            }
            finally {
                this.mappingRegistry.releaseReadLock();
            }
        }
    

    ** url 映射method在容器初始化的时候已经准备好**

    // 入口 开始声明的initStrategies() -->initHandlerMappings(context);会山路十八弯的调到
    AbstractHandlerMethodMapping#initHandlerMethods() {
        if (beanType != null && isHandler(beanType)) {
          detectHandlerMethods(beanName);
        }
    }
    -- isHandler(beanType)判断是否有@Controller || @RequestMapping注解
    //detectHandlerMethods 方法内
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    new MethodIntrospector.MetadataLookup<T>() {
        @Override
        public T inspect(Method method) {
            try {
                return getMappingForMethod(method, userType);
            }
            catch (Throwable ex) {
                throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
            }
        }
    });
    // 执行完上述方法之后methods ,Controller内带有RequestMapping的method为key, @RequestMapping封装成RequestMappingInfo为value
    
    Map<Method, T> methods =
    {
        public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.login(java.lang.String,java.lang.String,org.springframework.ui.Model)={[/login],methods=[POST]}
        , public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.home(org.springframework.ui.Model)={[/home],methods=[GET]}, 
        public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.logOut()={[/logout]}, 
        public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.layui()={[/layui]}
    }
    // 循环methods Map 构造另一种形式的map
    for (Map.Entry<Method, T> entry : methods.entrySet()) {
        Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
        T mapping = entry.getValue();
        registerHandlerMethod(handler, invocableMethod, mapping);
    }
    
    public void register(T mapping, Object handler, Method method) {
        this.readWriteLock.writeLock().lock();
        try {
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);
            assertUniqueMethodMapping(handlerMethod, mapping);
    
            if (logger.isInfoEnabled()) {
                logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
            }
            this.mappingLookup.put(mapping, handlerMethod);
    
            List<String> directUrls = getDirectUrls(mapping);
            for (String url : directUrls) {
                this.urlLookup.add(url, mapping);
            }
    
            String name = null;
            if (getNamingStrategy() != null) {
                name = getNamingStrategy().getName(handlerMethod, mapping);
                addMappingName(name, handlerMethod);
            }
    
            CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
            if (corsConfig != null) {
                this.corsLookup.put(handlerMethod, corsConfig);
            }
            // 添加到registry
            this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
        }
        finally {
            this.readWriteLock.writeLock().unlock();
        }
    }
    
    // 最终模样
    Map<T, MappingRegistration<T>> registry = 
    {
        {[/login],methods=[POST]}=org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistration@81e87eb
        , {[/home],methods=[GET]}=org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistration@6bb30dc5
    }
    
    AbstractHandlerMethodMapping$MappingRegistration {
        directUrls = [/login],
        handlerMethod = public java.lang.String ren.xuedao.moudle.sys.controller.LoginController.login(java.lang.String,java.lang.String,org.springframework.ui.Model),
        mapping = {[/login],methods=[POST]},
        mappingName = LC#login
    }
    
    1. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());用到了策略模式去匹配对应的
      HandlerAdapter一共有三种,即下图所示。作用就是去使用哪一种类型去处理请求。下面4中所示。


      Jietu20171017-214227@2x.jpg
    2. 前置过滤器拦截

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          return;
    }
    
    1. 实际执行
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      ServletInvocableHandlerMethod#invokeAndHandle
      4.1 调用 InvocableHandlerMethod#invokeForRequest
      4.1.1Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);InvocableHandlerMethod.getMethodArgumentValues(request, mavContainer, providedArgs);策略模式获取hand中方法的入参数组
      4.1.2 Object returnValue = doInvoke(args); 反射调用hand中的method
      4.2 调用this.returnValueHandlers.handleReturnValue(
      returnValue, getReturnValueType(returnValue), mavContainer, webRequest);对method的返回参数进行处理,也是策略模式。
    2. 后置过滤拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv);
    3. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);视图渲染、返回值处理
      6.1 render(mv, request, response);
      6.2 mappedHandler.triggerAfterCompletion(request, response, null);后置过滤器,释放资源,关闭连接
      ---未完待续 ,后续把图补上。

    相关文章

      网友评论

          本文标题:详解DispatcherServlet

          本文链接:https://www.haomeiwen.com/subject/zwrjuxtx.html