您的位置:首页 > 编程语言 > Java开发

SpringMVC源码分析

2020-12-10 15:04 176 查看

目录
  • 三,getHandler()方法分析
  • 四,getHandlerAdapter()方法——适配器获取分析
  • 五,SpringMVC九大组件初始化
  • 六,Handler方法细节刨析:
  • 七,processDispatchResult方法

    一,DispatcherServlet继承结构

    二、SpringMvc请求处理的大致流程

    2.1 Handler方法执行的时机

    打断点:

    观察调用栈:

    doDispathch⽅法中的1064⾏代码完成handler⽅法的调⽤

    2.2 页面渲染时机(打断点并观察调用栈)

    3.3 doDispatch()方法核心步骤 (Springmvc处理请求的大致流程):

    1. 调用
      getHandler()
      获取到能够处理当前请求的执行链
      HandlerExecutionChain
      (Handler + 拦截器)
    2. 调用
      getHandlerAdapter()
      获取能够执行Handler的适配器
    3. 适配器调用Handler执行
      ha.handle()
      ,总会返回一个ModelAndView对象
    4. 调用
      processDispatchResult()
      方法完成视图跳转
    //org.springframework.web.servlet.DispatcherServlet
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    //执行器链,包含了handler和一些拦截器
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    //异步管理器
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    try {
    ModelAndView mv = null;
    Exception dispatchException = null;
    
    try {
    //1. 检查是否是文件上传的请求
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);
    
    // Determine handler for the current request.
    /*
    2. 取得处理当前请求的Controller,这里也称为Handler,即处理器。这里并不是直接返回controller,
    而是返回HandlerExecutionChain  请求处理链对象 该对象封装了Handler和Inteceptor
    */
    mappedHandler = getHandler(
    1044
    processedRequest);
    if (mappedHandler == null) {
    // 如果handler为空, 则返回404
    noHandlerFound(processedRequest, response);
    return;
    }
    
    // Determine handler adapter for the current request.
    // 3. 获取处理请求的处理器适配器 HandlerAdapter
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // Process last-modified header, if supported by the handler.
    // 处理last-modeified 请求头
    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;
    }
    
    // Actually invoke the handler.
    // 4 实际处理器处理请求,返回结果视图对象
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    if (asyncManager.isConcurrentHandlingStarted()) {
    return;
    }
    //结果视图对象的处理
    applyDefaultViewName(processedRequest, mv);
    
    //==============拦截器的第二个拦截时机
    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);
    }
    //跳转视图页面,渲染视图
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}
    catch (Exception ex) {
    //最终会调用HandlerInterceptor的afterCompletion方法
    //========拦截器的第三个拦截时机————视图页面渲染完成之后拦截
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
    //最终会调用HandlerInterceptor的afterCompletion方法
    //========拦截器的第三个拦截时机————视图页面渲染完成之后拦截
    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);
    }
    }
    }
    }

    三,getHandler()方法分析

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //handlerMappings是一个 ArrayList ———— List<HandlerMapping> handlerMappings
    //而HandlerMapping 则存储了url和handler的映射关系
    if (this.handlerMappings != null) {
    /**
    * 遍历 handlerMappings :
    * 	1. BeanNameUrlHandlerMapping ,早期的一种使用方式
    * 	2. RequestMappingHandlerMapping,我们的请求所使用的
    */
    for (HandlerMapping mapping : this.handlerMappings) {
    HandlerExecutionChain handler = mapping.getHandler(request);
    if (handler != null) {
    return handler;
    }
    }
    }
    return null;
    }

    HandlerExecutionChain 包含了 DemoController.handle01 以及 0个 interceptors

    Q:HandlerMapping里面的映射关系是在何时进行初始化的?

    A:在容器启动时时,IOC容器在扫描@Controller对象时会扫描@RequestMapping注解,然后就可 25ec 以建立url和handler方法的映射关系

    四,getHandlerAdapter()方法——适配器获取分析

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    //List<HandlerAdapter> handlerAdapters
    if (this.handlerAdapters != null) {
    /*
    遍历 handlerAdapters:
    遍历各个HandlerAdapter,看哪个Adapter⽀持处理当前Handler:
    handlerAdapters是一个List<HandlerAdapter>,HandlerAdapter是一个接口,里面有几个实现类:
    1. HttpRequestHandlerAdapter ——实现接口的方式
    2. SimpleControllerHandlerAdapter ——实现Controller接口的方式
    3. RequestMappingHandlerAdapter ——是不是HandlerMethod(RequestMappingHandlerMapping封装的)的实例
    */
    for (HandlerAdapter adapter : this.handlerAdapters) {
    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");
    }

    Q:handlerAdapters 中三个 实现类是如何初始化的?

    A:这些组件简单的说也是容器启动时初始化的。

    五,SpringMVC九大组件初始化

    5.1 九大组件

    //org.springframework.web.servlet.DispatcherServlet
    
    //多部件解析器,文件上传之类的
    @Nullable
    private MultipartResolver multipartResolver;
    
    //区域化 国际化解析器
    @Nullable
    private LocaleResolver localeResolver;
    
    //主题解析器
    @Nullable
    private ThemeResolver themeResolver;
    
    //处理器映射器组件
    @Nullable
    private List<HandlerMapping> handlerMappings;
    
    //处理器适配器组件
    @Nullable
    private List<HandlerAdapter> handlerAdapters;
    
    //异常解析器
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    //默认视图名转换器组件
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;
    
    //flash属性管理组件
    @Nullable
    private FlashMapManager flashMapManager;
    
    //视图解析器
    @Nullable
    private List<ViewResolver> viewResolvers;

    上述九大组件都是定义了接口,接口其实是定义了规范。

    5.2 九大组件初始化细节:

    //org.springframework.web.servlet.DispatcherServlet
    
    //主要完成组件的初始化
    @Override
    protected void onRefresh(ApplicationContext context) {
    //初始化策略
    initStrategies(context);
    }
    protected void initStrategies(ApplicationContext context) {
    // 多文件上传的组件
    initMultipartResolver(context);
    // 初始化本地语语言环境
    initLocaleResolver(context);
    // 初始化模板处理器
    initThemeResolver(context);
    // 初始化HandlerMapping
    initHandlerMappings(context);
    // 初始化参数适配器
    initHandlerAdapters(context);
    // 初始化异常拦截器
    initHandlerExceptionResolvers(context);
    // 初始化视图预处理器
    initRequestToViewNameTranslator(context);
    // 初始化视图转换器
    initViewResolvers(context);
    // 初始化FlashMap 管理器
    initFlashMapManager(context);
    }

    onRefresh方法何时被调用?

    在此方法中打一个断点,然后Debug模式启动,然后观察调用栈。


    可以看到,最初是由

    refresh
    方法调用的——
    finishRefresh()
    ,由
    finishRefresh()
    发布事件,然后触发事件监听,最终到了
    onRefresh
    方法。

    重点来看:

    5.2.1 initHandlerMappings(context)

    默认的配置:

    initHandlerAdapters同理

    ***注意 多文件上传的组件(MultipartResolver)必须按照id注册对象:

    六,Handler方法细节刨析:

    //org.springframework.web.servlet.DispatcherServlet#doDispatch
    
    // 4 实际处理器处理请求,返回结果视图对象
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());


    七,processDispatchResult方法

    //跳转视图页面,渲染视图
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

    render方法完成渲染

  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: