摸透Spring MVC真正如何工作核心原理(part:2)

通過優銳課核心Spring MVC學習筆記中,我們可以看到Spring MVC中包含的功能可以在Web應用程序中發揮巨大作用的強大功能,一起來看看。

這裏看着很迷的小夥伴可以去我主頁,翻前面的第一章節學習。
摸透Spring MVC真正如何工作核心原理(part:1)

10、DispatcherServlet:統一請求處理
HttpServlet.service()實現通過HTTP動詞的類型路由請求,在低級servlet的上下文中非常有意義。 但是,在Spring MVC的抽象級別上,方法類型只是可用於將請求映射到其處理程序的參數之一。
因此,FrameworkServlet類的另一個主要功能是將處理邏輯重新加入到單個processRequest()方法中,該方法又調用doService()方法:

@Override
protected final void doGet(HttpServletRequest request, 
  HttpServletResponse response) throws ServletException, IOException {
    processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, 
  HttpServletResponse response) throws ServletException, IOException {
    processRequest(request, response);
}
// …

11、DispatcherServlet:豐富請求
最後,DispatcherServlet實現doService()方法。 在這裏,它向請求中添加了一些有用的對象,這些對象可能會在處理管道中派上用場:Web應用程序上下文,語言環境解析器,主題解析器,主題源等:

request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, 
  getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

此外,doService()方法還準備輸入和輸出閃存映射。 Flash映射基本上是一種將參數從一個請求傳遞到緊隨其後的另一個請求的模式。 這在重定向過程

FlashMap inputFlashMap = this.flashMapManager
  .retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
    request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, 
      Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());

然後,doService()方法調用負責請求分派的doDispatch()方法。

12、DispatcherServlet:分派請求

dispatch()方法的主要目的是爲請求找到合適的處理程序,並向其提供請求/響應參數。 處理程序基本上是任何類型的對象,並且不限於特定的接口。 這也意味着Spring需要爲此處理程序找到一個適配器,該適配器知道如何與處理程序“對話”。

爲了找到與請求匹配的處理程序,Spring會通過HandlerMapping接口的註冊實現。 有許多不同的實現方式可以滿足你的需求。
SimpleUrlHandlerMapping允許通過URL將請求映射到某個處理Bean。 例如,可以通過向其映射屬性注入類似於以下內容的java.util.Properties實例來配置它:

/welcome.html=ticketController
/show.html=ticketController

處理程序映射最廣泛使用的類可能是RequestMappingHandlerMapping,它將請求映射到@Controller類的@RequestMapping註釋方法。 這正是將調度程序與控制器的hello()和login()方法連接起來的映射。

請注意,你的Spring感知方法分別以@GetMapping和@PostMapping註釋。 這些註解又以@RequestMapping元註解標記。

dispatch()方法還負責其他一些HTTP特定的任務:

在未修改資源的情況下,對GET請求進行短路處理

將多部分解析器應用於相應的請求

如果處理程序選擇異步處理請求,則對請求進行短路處理

13、處理請求

現在,Spring確定了請求的處理程序和處理程序的適配器,是時候最終處理請求了。 這是HandlerAdapter.handle()方法的簽名。 請務必注意,處理程序可以選擇如何處理請求:

將數據本身寫入響應對象並返回null

返回要由DispatcherServlet渲染的ModelAndView對象

@Nullable
ModelAndView handle(HttpServletRequest request, 
                    HttpServletResponse response, 
                    Object handler) throws Exception;

提供了幾種類型的處理程序。 這是SimpleControllerHandlerAdapter處理Spring MVC控制器實例的方式(不要將其與帶有@Controller註釋的POJO混淆)。
請注意,控制器處理程序如何返回ModelAndView對象,並且不會自行渲染視圖:

public ModelAndView handle(HttpServletRequest request, 
  HttpServletResponse response, Object handler) throws Exception {
    return ((Controller) handler).handleRequest(request, response);
}

第二個是SimpleServletHandlerAdapter,它將常規Servlet用作請求處理程序。
Servlet對ModelAndView一無所知,只是簡單地自行處理請求,將結果呈現到響應對象中。 因此,此適配器僅返回null而不是ModelAndView:

public ModelAndView handle(HttpServletRequest request, 
  HttpServletResponse response, Object handler) throws Exception {
    ((Servlet) handler).service(request, response);
    return null;
}

在你的情況下,控制器是帶有多個@RequestMapping批註的POJO,因此任何處理程序基本上都是包裝在HandlerMethod實例中的此類方法。 爲了適應這種處理程序類型,Spring使用了RequestMappingHandlerAdapter類。

14、處理參數和處理程序方法的返回值

請注意,控制器方法通常不採用HttpServletRequest和HttpServletResponsearguments,而是接收和返回許多不同類型的數據,例如域對象,路徑參數等。

另外,請注意,你不需要從控制器方法返回ModelAndView實例。 你可以返回視圖名稱,ResponseEntity或將轉換爲JSON響應的POJO等。
RequestMappingHandlerAdapter確保從HttpServletRequest解析方法的參數。 此外,它還會根據方法的返回值創建ModelAndView對象。
RequestMappingHandlerAdapter中有一段重要的代碼可以確保所有這種轉換魔術都發生了:

ServletInvocableHandlerMethod invocableMethod 
  = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
    invocableMethod.setHandlerMethodArgumentResolvers(
      this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
    invocableMethod.setHandlerMethodReturnValueHandlers(
      this.returnValueHandlers);
}

argumentResolvers對象是不同的HandlerMethodArgumentResolver實例的組合。
有30多種不同的參數解析器實現。 它們允許從請求中提取任何種類的信息,並將其作爲方法參數提供。 這包括URL路徑變量,請求主體參數,請求標頭,cookie,會話數據等。

returnValueHandlers對象是HandlerMethodReturnValueHandler對象的組合。 還有很多不同的值處理程序可以處理方法的結果以創建適配器期望的ModelAndView對象。
例如,當你從hello()方法返回字符串時,ViewNameMethodReturnValueHandler處理該值。 但是當你從login()方法返回一個現成的ModelAndView時,Spring使用ModelAndViewMethodReturnValueHandler。

15、渲染視圖

到目前爲止,Spring已經處理了HTTP請求並收到了ModelAndView對象,因此它必須呈現用戶將在瀏覽器中看到的HTML頁面。它基於封裝在ModelAndView對象中的模型和所選視圖進行操作。

還要注意,你可以呈現JSON對象,XML或可以通過HTTP協議傳輸的任何其他數據格式。我們將在下面的REST重點部分中詳細介紹這一點。

讓我們回到DispatcherServlet。首先,render()方法使用提供的LocaleResolver實例設置響應區域設置。假設你的現代瀏覽器正確設置了Accept標頭,並且默認情況下使用了AcceptHeaderLocaleResolver。

在渲染期間,ModelAndView對象可能已經包含對選定視圖的引用,或者僅包含視圖名稱,或者如果控制器依賴於默認視圖則根本不包含任何內容。
由於hello()和login()方法都將所需的視圖指定爲字符串名稱,因此必須使用該名稱進行查找。因此,這是viewResolvers列表起作用的地方:

for (ViewResolver viewResolver : this.viewResolvers) {
    View view = viewResolver.resolveViewName(viewName, locale);
    if (view != null) {
        return view;
    }
}

這是ViewResolver實例的列表,包括由thymeleaf-spring5集成庫提供的ThymeleafViewResolver。 該解析器知道在哪裏搜索視圖,並提供相應的視圖實例。
調用視圖的render()方法後,Spring最終通過將HTML頁面發送到用戶的瀏覽器來完成請求處理:

16、REST支持

除了典型的MVC場景之外,我們還可以使用該框架來創建REST Web服務。
簡而言之,你可以接受資源作爲輸入,將POJO指定爲方法參數,然後使用@RequestBody對其進行註釋。 你還可以使用@ResponseBody註釋方法本身,以指定其結果必須直接轉換爲HTTP響應:

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
@ResponseBody
@PostMapping("/message")
public MyOutputResource sendMessage(
  @RequestBody MyInputResource inputResource) {
    return new MyOutputResource("Received: "
      + inputResource.getRequestMessage());
}

由於Spring MVC的可擴展性,這也是可能的。

爲了將內部DTO編組爲REST表示形式,該框架使用了HttpMessageConverter基礎結構。 例如,實現之一是MappingJackson2HttpMessageConverter,它能夠使用Jackson庫將模型對象與JSON相互轉換。

爲了進一步簡化REST API的創建,Spring引入了@RestController註釋。 在默認情況下假設@ResponseBody語義是很方便的,並且避免在每個REST控制器上顯式設置它:

import org.springframework.web.bind.annotation.RestController;
@RestController
public class RestfulWebServiceController {
    @GetMapping("/message")
    public MyOutputResource getMessage() {
        return new MyOutputResource("Hello!");
    }
}

結論
文章寫道這裏,已經爲你詳細介紹了關於Spring MVC框架中的請求處理。 相信你已經瞭解了框架的各種擴展如何協同工作,以提供所有魔力,並使你不必處理HTTP協議的難處。
————————————————
還有就是這我總結出了一些架構視頻資料和互聯網公司java程序員面試涉及到的絕大部分面試題和答案做成了文檔和架構視頻資料還有完整高清的java進階架構學習路線圖free分享給大家(包括Dubbo、Redis、Netty、zookeeper、Springcloud、分佈式、高併發等架構技術資料),可以加vx:ddmsiqi領取
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章