最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解SpringMVC從基礎到源碼

 更新時間:2020年09月20日 09:26:28   作者:沸羊羊_  
這篇文章主要介紹了詳解SpringMVC從基礎到源碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

認識SpringMVC

SpringMVC 框架是以請求為驅動,圍繞 Servlet 設計,將請求發(fā)給控制器,然后通過模型對象,分派器來展示請求結果視圖。其中核心類是 DispatcherServlet,它是一個 Servlet,頂層是實現(xiàn)的Servlet接口。

SpringMVC 處理請求過程

 

  • 客戶端發(fā)起請求,會首先經過前端控制器 DispatcherServlet 進行轉發(fā),轉發(fā)到 Handler Mapping
  • DispatcherServlet 從 Handler Mapping 查找處理請求的 Controller,Handler Mapping 作用就是完成 URL 到 Controller 的映射
  • Controller 處理請求并返回 ModelAndView 對象,ModelAndView 是封裝結果視圖的組件
  • 再將視圖結果返回給客戶端

Servlet 與 SpringMVC

SpringMVC 是在 Servlet 的基礎上進行了擴展,看看他們的繼承關系是什么樣的。

Servlet 繼承關系

在這里插入圖片描述

SpringMVC 繼承關系

在這里插入圖片描述

Servlet 與 SpringMVC 對比

  • Servlet 需要每個請求都在 web.xml 文件中配置一個 sevlet 節(jié)點
  • SpringMVC 的 DispatcherServlet 會攔截所有請求,讓 Controller 去處理

Structs2 與 Spring MVC

相同點

都是基于MVC模型的

不同點

  • Structs2 是基于類的,一個 request 創(chuàng)建一個 action,一個action 對應一個 request ;Servlet 是基于方法的,也就是一個 request 對應一個方法
  • Structs2 入口是 Filter;SpringMVC 入口是 Servlet
  • SpringMVC 的開發(fā)速度和性能優(yōu)于 Structs2 ,流程更易理解
  • SpringMVC 和 Spring 是無縫的,可以認為 SpringMVC 是100% 零配置

SpringMVC源碼分析

1、ApplicationContext 初始化時建立所有的URL和Controller 的對應關系

/**
* 建立當前ApplicationContext中的所有controller和url的對應關系
*/
protected void detectHandlers() throws BeansException {
  //日志級別是否是 Debug
  if (logger.isDebugEnabled()) {
    //應用上下文就是工程的訪問路徑
    logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
  }
     // 獲取ApplicationContext容器中所有bean的Name---Controller
  String[] beanNames = (this.detectHandlersInAncestorContexts ?
      BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
      getApplicationContext().getBeanNamesForType(Object.class));

  // 遍歷beanNames,并找到這些bean對應的url
  for (String beanName : beanNames) {
       // 獲取Controller上的所有url(類上的url+方法上的url)
    String[] urls = determineUrlsForHandler(beanName);
    if (!ObjectUtils.isEmpty(urls)) {
      // 保存urls和beanName的對應關系,put it to Map<urls,beanName>,該方法在父類AbstractUrlHandlerMapping中實現(xiàn)
      registerHandler(urls, beanName);
    }
    else {
      if (logger.isDebugEnabled()) {
        logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
      }
    }
  }
}

2、根據(jù)訪問URL找到對應 Controller 中處理請求的方法

/** 中央控制器,控制請求的轉發(fā) **/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;

try {
  ModelAndView mv;
  boolean errorView = false;
  try {
    // 1.檢查是否是文件上傳的請求
    processedRequest = checkMultipart(request);

    // 2.取得處理當前請求的controller,這里也稱為hanlder,處理器,第一個步驟的意義就在這里體現(xiàn)了.
    這里并不是直接返回controller,而是返回的HandlerExecutionChain請求處理器鏈對象,該對象封裝了handler和interceptors.
    mappedHandler = getHandler(processedRequest, false);
    // 如果handler為空,則返回404
    if (mappedHandler == null || mappedHandler.getHandler() == null) {
      noHandlerFound(processedRequest, response);
      return;
    }
    //3. 獲取處理request的處理器適配器handler adapter 
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // 處理 last-modified 請求頭
    String method = request.getMethod();
    boolean isGet = "GET".equals(method);
    if (isGet || "HEAD".equals(method)) {
      long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
      if (logger.isDebugEnabled()) {
        String requestUri = urlPathHelper.getRequestUri(request);
        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
      }
      if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
        return;
      }
    }

    // 4.攔截器的預處理方法
    HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
    if (interceptors != null) {
      for (int i = 0; i < interceptors.length; i++) {
        HandlerInterceptor interceptor = interceptors[i];
        if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
          triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
          return;
        }
        interceptorIndex = i;
      }
    }

    // 5.實際的處理器處理請求,返回結果視圖對象
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    // 結果視圖對象的處理
    if (mv != null && !mv.hasView()) {
      mv.setViewName(getDefaultViewName(request));
    }

    // 6.攔截器的后處理方法
    if (interceptors != null) {
      for (int i = interceptors.length - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = interceptors[i];
        interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
      }
    }
  }
  catch (ModelAndViewDefiningException ex) {
    logger.debug("ModelAndViewDefiningException encountered", ex);
    mv = ex.getModelAndView();
  }
  catch (Exception ex) {
    Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
    mv = processHandlerException(processedRequest, response, handler, ex);
    errorView = (mv != null);
  }

  
  if (mv != null && !mv.wasCleared()) {
    render(mv, processedRequest, 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");
    }
  }

  // 請求成功響應之后的方法
  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}

3、反射調用處理請求的方法返回結果視圖

/** 獲取處理請求的方法,執(zhí)行并返回結果視圖 **/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
	throws Exception {
  // 1.獲取方法解析器
  ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);     
  // 2.解析request中的url,獲取處理request的方法 
  //通過 request 找 controller 中的處理方法,request的url與 controller 的url 進行匹配
  Method handlerMethod = methodResolver.resolveHandlerMethod(request);     
  // 3.方法調用器
  ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  ExtendedModelMap implicitModel = new BindingAwareModelMap();
     // 4.執(zhí)行方法
  Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);     
  // 5.封裝結果視圖
  ModelAndView mav =
      methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
  methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
  return mav;
}

到此這篇關于詳解SpringMVC從基礎到源碼的文章就介紹到這了,更多相關SpringMVC 源碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • JavaFX實現(xiàn)簡易時鐘效果(一)

    JavaFX實現(xiàn)簡易時鐘效果(一)

    這篇文章主要為大家詳細介紹了JavaFX實現(xiàn)簡易時鐘效果的第一篇,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Spring Cloud如何切換Ribbon負載均衡模式

    Spring Cloud如何切換Ribbon負載均衡模式

    這篇文章主要介紹了Spring Cloud如何切換Ribbon負載均衡模式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • IDEA報錯之前言中不允許有內容問題及解決

    IDEA報錯之前言中不允許有內容問題及解決

    當使用IntelliJ IDEA時,可能會遇到報錯信息“前言中不允許有內容”,這通常是由于XML文件是以帶有BOM頭的UTF-8格式保存的,導致IDE的解析出錯,解決辦法是在IDEA中調整文件編碼設置為無BOM的UTF-8,然后用文本編輯器(如Notepad++)
    2024-10-10
  • 解決打開的idea項目maven不生效問題

    解決打開的idea項目maven不生效問題

    這篇文章主要給大家介紹了關于如何解決打開的idea項目maven不生效問題,最近在配置maven時,發(fā)現(xiàn)無論配置幾遍,IDEA中的maven配置總會還原成默認的,所以這里給大家分享下解決辦法,需要的朋友可以參考下
    2023-07-07
  • 如何實現(xiàn)自定義SpringBoot的Starter組件

    如何實現(xiàn)自定義SpringBoot的Starter組件

    這篇文章主要介紹了實現(xiàn)自定義SpringBoot的Starter組件的示例代碼,想要自定義starter組件,首先要了解springboot是如何加載starter的,也就是springboot的自動裝配機制原理,本文結合示例代碼詳細講解,需要的朋友可以參考下
    2023-02-02
  • SpringCloud+nacos部署在多ip環(huán)境下統(tǒng)一nacos服務注冊ip(親測有效)

    SpringCloud+nacos部署在多ip環(huán)境下統(tǒng)一nacos服務注冊ip(親測有效)

    在部署SpringCoud項目的時候分服務器部署注冊同一個nacos服務,但是在服務器有多個ip存在的同時(內外網),就會出現(xiàn)注冊服務ip不同的問題,導致一些接口無法連接訪問,經過多次排查終于找到問題并找到解決方法,需要的朋友可以參考下
    2023-04-04
  • 使用反射方式獲取JPA Entity的屬性和值

    使用反射方式獲取JPA Entity的屬性和值

    這篇文章主要介紹了使用反射方式獲取JPA Entity的屬性和值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • java實現(xiàn)字符串四則運算公式解析工具類的方法

    java實現(xiàn)字符串四則運算公式解析工具類的方法

    今天小編就為大家分享一篇java實現(xiàn)字符串四則運算公式解析工具類的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • springboot接口參數(shù)為List的問題

    springboot接口參數(shù)為List的問題

    這篇文章主要介紹了springboot接口參數(shù)為List的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java為什么匿名內部類參數(shù)引用需要用final進行修飾?

    Java為什么匿名內部類參數(shù)引用需要用final進行修飾?

    今天小編就為大家分享一篇關于Java為什么匿名內部類參數(shù)引用需要用final進行修飾?,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04

最新評論

吴江市| 成武县| 田林县| 勃利县| 蒙阴县| 临澧县| 宝应县| 北川| 铁岭县| 抚远县| 咸丰县| 天等县| 遂宁市| 廉江市| 偃师市| 繁峙县| 辽中县| 凤山县| 延庆县| 马鞍山市| 古田县| 大宁县| 怀化市| 威信县| 长海县| 丹阳市| 沙雅县| 石景山区| 仙游县| 舞阳县| 定日县| 宁城县| 南安市| 青河县| 保亭| 镇坪县| 南宫市| 桂东县| 灵宝市| 静安区| 泸水县|