SpringMVC源码--DispatcherServlet

1、前端控制器的架构:DispatcherServlet

2、DispatcherServlet() 细节:

 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;
                Object dispatchException = null;

                try {
                    //*1、检查是否文件上传请求
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    //2、根据当前的请求地址找到哪个类能来处理
                    mappedHandler = this.getHandler(processedRequest);
                    //3、如果没有找到相应的控制器来处理这个请求,就报404或者抛异常
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                    //4、拿到能执行这个类的所有方法的适配器(反射工具)
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //处理(控制)器的方法被调用了
                    //控制器(Controller),处理器(Handler)
                    //5、适配器执行目标方法,将目标方法执行完成后的返回值作为视图名,设置保存到
                    //ModelAndView中
             //目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView 
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    //如果没有视图名,设置一个默认的视图名
                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                //转发到目标页面的
                //6、根据方法最终执行完成封装的ModelAndView,转发到对应页面,
                //而且ModelAndView中的数据可以从请求域中获取
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

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

        }
    }

 流程总结:
    1、所有的请求过来,DispatcherServlet收到请求,
    2、调用doDispathc()方法方法进行处理:
            1)、getHandler():根据当前请求地址找到能处理这个请求的目标处理类(处理器)
                            根据当前请求在HandlerMapping中找到能处理这个请求的映射信息,获取到目标处理器类
            2)、getHandlerAdapter():根据当前处理类获取到能执行这个处理器方法的适配器
                            根据当前处理器类,找到当前类的HandlerAdapter(适配器)
            3)、使用刚刚获取到的适配器(AnnotationMethodHandlerAdapter)执行目标方法
            4)、目标方法执行后会返回一个ModelAndView对象
            5)、根据ModelAndView的信息发送到具体的页面,并可以在请求域中取出ModelAndView中的模型数据 


2.1、 getHandler() 细节:怎么根据当前请求就能找到哪个类能来处理 

getHandler() 会返回目标处理器的执行链(HandlerExecutionChain)

handlerMapping的handlerMap为什么会有值?:IOC容器一启动,就会创建标有注解@Controller的组件对象,然后扫描 @RequsetMapping能处理什么请求,只要扫描到了就会保存handlerMap中,下一次请求过来,就看哪个HandlerMapping中有这个请求映射信息就行了 

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            //遍历handlerMappings中的handlerMapping
            //handlerMappings是一个ArrayList
            //handlerMappings中有两个handlerMapping
            //一个是:BeanNameUrlHandlerMapping
            //一个是:DefaultAnnotationHandlerMapping
            //handlerMapping中的handlerMap中有值
            if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

2.2、getHandlerAdapter() 细节

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }

        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

    @Nullable
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {
        request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        ModelAndView exMv = null;
        if (this.handlerExceptionResolvers != null) {
            Iterator var6 = this.handlerExceptionResolvers.iterator();

            while(var6.hasNext()) {
                HandlerExceptionResolver resolver = (HandlerExceptionResolver)var6.next();
                exMv = resolver.resolveException(request, response, handler, ex);
                if (exMv != null) {
                    break;
                }
            }
        }

        if (exMv != null) {
            if (exMv.isEmpty()) {
                request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                return null;
            } else {
                if (!exMv.hasView()) {
                    String defaultViewName = this.getDefaultViewName(request);
                    if (defaultViewName != null) {
                        exMv.setViewName(defaultViewName);
                    }
                }

                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Using resolved error view: " + exMv, ex);
                } else if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Using resolved error view: " + exMv);
                }

                WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
                return exMv;
            }
        } else {
            throw ex;
        }
    }

2.3 DispatcherServlet九大组件 

SpringMVC在工作的时候,关键位置都是由这些组件完成的;

共同点:全部都是接口,接口就是规范,提供了强大的扩展性

    @Nullable
    //文件上传解析器
    private MultipartResolver multipartResolver;
    @Nullable
    //区域信息解析器:和国际化有关
    private LocaleResolver localeResolver;
    @Nullable
    //主题解析器
    private ThemeResolver themeResolver;
    @Nullable
    //Handler映射信息
    private List<HandlerMapping> handlerMappings;
    @Nullable
    //Handler适配器
    private List<HandlerAdapter> handlerAdapters;
    @Nullable
    //SpringMVC异常解析功能:异常解析器
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    @Nullable
    
    private RequestToViewNameTranslator viewNameTranslator;
    @Nullable
    //SpringMVC中允许重定向携带数据的功能
    private FlashMapManager flashMapManager;
    @Nullable
    //视图解析器
    private List<ViewResolver> viewResolvers;

DispatcherServlet中九大组件初始化的地方:服务器一启动就要初始化,初始的时候去容器中找,找不到就使用默认配置

可以在web.xml中修改DispatcherServlet的某些默认配置

protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }
protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

例如初始化HandlerMappings

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } else {
            try {
                HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

2.4 mv = ha.handle 执行目标方法的细节

 @RequestMapping("/user")
    public String user(User user,
                       Map<String,Object> map,
                       Model model,
                       @RequestParam(value = "name")String name)
    @Nullable
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return this.handleInternal(request, response, (HandlerMethod)handler);
    }
    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader("Cache-Control")) {
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }

        return mav;
    }
 @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        Object result;
        try {
            WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
            ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
            if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }

            if (this.returnValueHandlers != null) {
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }

            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
            if (asyncManager.hasConcurrentResult()) {
                result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
            if (!asyncManager.isConcurrentHandlingStarted()) {
                ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
                return var15;
            }

            result = null;
        } finally {
            webRequest.requestCompleted();
        }

        return (ModelAndView)result;
    }

两件事:

1、运行流程简单版

2、确定方法每个参数的值:

        1、标注解:保存注解的信息,最终得到这个注解应该对应解析的值

        2、没标注解:

                 1)、看是否是原生API;

                 2)、看是否是Model或者Map.xxx

                 3)、都不是,看是否是简单类型:paramName

                 4)、getattrName(参数标了@ModelAttribure("")就是指定的,没有标题的就是"")

                        确定自定义类型参数:

                          1)、attrName使用参数的类型首字母小写;或者使用之前@ModelAttribute("")的值

                          2)、先看隐含模型中有没有这个attrName作为key对应的值,如果有就从隐含模型中获取并赋值

                          3)、看是否是@SessionAtrribute(value=""haha),标注的属性,如果是从session中拿,如果拿不到就抛异常

                          4)、不是@SessionAtrribute标注的,利用反射创建一个对象

                          5)、拿到之前创建好的对象,使用数据绑定器(WebDataBinder)将请求中的每个数据绑定到这个对象中;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值