日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

SpringMVC工作原理之一:DispatcherServlet

發(fā)布時(shí)間:2025/3/21 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringMVC工作原理之一:DispatcherServlet 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、DispatcherServlet 處理流程

在整個(gè) Spring MVC 框架中,DispatcherServlet 處于核心位置,它負(fù)責(zé)協(xié)調(diào)和組織不同組件完成請(qǐng)求處理并返回響應(yīng)工作。在看 DispatcherServlet 類(lèi)之前,我們先來(lái)看一下請(qǐng)求處理的大致流程:

  • Tomcat 啟動(dòng),對(duì) DispatcherServlet 進(jìn)行實(shí)例化,然后調(diào)用它的 init() 方法進(jìn)行初始化,在這個(gè)初始化過(guò)程中完成了:
  • 對(duì) web.xml 中初始化參數(shù)的加載;建立 WebApplicationContext (SpringMVC的IOC容器);進(jìn)行組件的初始化;
  • 客戶端發(fā)出請(qǐng)求,由 Tomcat 接收到這個(gè)請(qǐng)求,如果匹配 DispatcherServlet 在 web.xml 中配置的映射路徑,Tomcat 就將請(qǐng)求轉(zhuǎn)交給 DispatcherServlet 處理;
  • DispatcherServlet 從容器中取出所有 HandlerMapping 實(shí)例(每個(gè)實(shí)例對(duì)應(yīng)一個(gè) HandlerMapping 接口的實(shí)現(xiàn)類(lèi))并遍歷,每個(gè)?HandlerMapping 會(huì)根據(jù)請(qǐng)求信息,通過(guò)自己實(shí)現(xiàn)類(lèi)中的方式去找到處理該請(qǐng)求的 Handler (執(zhí)行程序,如Controller中的方法),并且將這個(gè) Handler 與一堆?HandlerInterceptor (攔截器) 封裝成一個(gè)?HandlerExecutionChain 對(duì)象,一旦有一個(gè) HandlerMapping 可以找到 Handler 則退出循環(huán);(詳情可以看?[Java]SpringMVC工作原理之二:HandlerMapping和HandlerAdpater?這篇文章)
  • DispatcherServlet 取出 HandlerAdapter 組件,根據(jù)已經(jīng)找到的 Handler,再?gòu)乃?HandlerAdapter 中找到可以處理該 Handler 的 HandlerAdapter 對(duì)象;
  • 執(zhí)行 HandlerExecutionChain 中所有攔截器的 preHandler() 方法,然后再利用 HandlerAdapter 執(zhí)行 Handler ,執(zhí)行完成得到 ModelAndView,再依次調(diào)用攔截器的 postHandler() 方法;
  • 利用 ViewResolver?將 ModelAndView 或是 Exception(可解析成 ModelAndView)解析成 View,然后 View 會(huì)調(diào)用 render() 方法再根據(jù) ModelAndView 中的數(shù)據(jù)渲染出頁(yè)面;
  • 最后再依次調(diào)用攔截器的?afterCompletion() 方法,這一次請(qǐng)求就結(jié)束了。
  • ?

    二、DispatcherServlet 源碼分析

    DispatcherServlet 繼承自 HttpServlet,它遵循 Servlet 里的“init-service-destroy”三個(gè)階段,首先我們先來(lái)看一下它的 init() 階段。

    1 初始化

    1.1?HttpServletBean 的 init() 方法

    DispatcherServlet 的 init() 方法在其父類(lèi)?HttpServletBean?中實(shí)現(xiàn)的,它覆蓋了 GenericServlet 的 init() 方法,主要作用是加載 web.xml 中 DispatcherServlet 的?<init-param> 配置,并調(diào)用子類(lèi)的初始化。下面是 init() 方法的具體代碼:

    @Override public final void init() throws ServletException {try {// ServletConfigPropertyValues 是靜態(tài)內(nèi)部類(lèi),使用 ServletConfig 獲取 web.xml 中配置的參數(shù)PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);// 使用 BeanWrapper 來(lái)構(gòu)造 DispatcherServletBeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);} catch (BeansException ex) {}// 讓子類(lèi)實(shí)現(xiàn)的方法,這種在父類(lèi)定義在子類(lèi)實(shí)現(xiàn)的方式叫做模版方法模式initServletBean(); }

    ?

    1.2?FrameworkServlet 的 initServletBean() 方法

    在 HttpServletBean 的?init() 方法中調(diào)用了?initServletBean() 這個(gè)方法,它是在?FrameworkServlet?類(lèi)中實(shí)現(xiàn)的,主要作用是建立 WebApplicationContext 容器(有時(shí)也稱(chēng)上下文),并加載 SpringMVC 配置文件中定義的 Bean 到改容器中,最后將該容器添加到 ServletContext 中。下面是?initServletBean() 方法的具體代碼:

    @Override protected final void initServletBean() throws ServletException {try {// 初始化 WebApplicationContext (即SpringMVC的IOC容器)this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();} catch (ServletException ex) {} catch (RuntimeException ex) {} }

    WebApplicationContext 繼承于 ApplicationContext 接口,從容器中可以獲取當(dāng)前應(yīng)用程序環(huán)境信息,它也是 SpringMVC 的 IOC 容器。下面是 initWebApplicationContext() 方法的具體代碼:

    protected WebApplicationContext initWebApplicationContext() {// 獲取 ContextLoaderListener 初始化并注冊(cè)在 ServletContext 中的根容器,即 Spring 的容器WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {// 因?yàn)?WebApplicationContext 不為空,說(shuō)明該類(lèi)在構(gòu)造時(shí)已經(jīng)將其注入wac = this.webApplicationContext;if (wac instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;if (!cwac.isActive()) {if (cwac.getParent() == null) {// 將 Spring 的容器設(shè)為 SpringMVC 容器的父容器cwac.setParent(rootContext);}configureAndRefreshWebApplicationContext(cwac);}}}if (wac == null) {// 如果 WebApplicationContext 為空,則進(jìn)行查找,能找到說(shuō)明上下文已經(jīng)在別處初始化。wac = findWebApplicationContext();}if (wac == null) {// 如果 WebApplicationContext 仍為空,則以 Spring 的容器為父上下文建立一個(gè)新的。wac = createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {// 模版方法,由 DispatcherServlet 實(shí)現(xiàn)onRefresh(wac);}if (this.publishContext) {// 發(fā)布這個(gè) WebApplicationContext 容器到 ServletContext 中String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac; }

    下面是查找?WebApplicationContext 的?findWebApplicationContext() 方法代碼:

    protected WebApplicationContext findWebApplicationContext() {String attrName = getContextAttribute();if (attrName == null) {return null;}// 從 ServletContext 中查找已經(jīng)發(fā)布的 WebApplicationContext 容器WebApplicationContext wac =WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);if (wac == null) {throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");}return wac; }

    ?

    1.3 DispatcherServlet 的 onRefresh() 方法

    建立好?WebApplicationContext(上下文)?后,通過(guò) onRefresh(ApplicationContext context) 方法回調(diào),進(jìn)入 DispatcherServlet 類(lèi)中。onRefresh() 方法,提供 SpringMVC 的初始化,具體代碼如下:

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

    在 initStrategies() 方法中進(jìn)行了各個(gè)組件的初始化,先來(lái)看一下這些組件的初始化方法,稍后再來(lái)詳細(xì)分析這些組件。

    1.3.1?initHandlerMappings 方法

    initHandlerMappings() 方法從?SpringMVC 的容器及 Spring 的容器中查找所有的 HandlerMapping 實(shí)例,并把它們放入到?handlerMappings 這個(gè) list 中。這個(gè)方法并不是對(duì)?HandlerMapping 實(shí)例的創(chuàng)建,HandlerMapping 實(shí)例是在上面 WebApplicationContext 容器初始化,即 SpringMVC 容器初始化的時(shí)候創(chuàng)建的。

    private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// 從 SpringMVC 的 IOC 容器及 Spring 的 IOC 容器中查找 HandlerMapping 實(shí)例Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// 按一定順序放置 HandlerMapping 對(duì)象OrderComparator.sort(this.handlerMappings);}} else {try {HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);} catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// 如果沒(méi)有 HandlerMapping,則加載默認(rèn)的if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);} }

    1.3.2?initHandlerAdapters 方法

    private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());// We keep HandlerAdapters in sorted order.OrderComparator.sort(this.handlerAdapters);}} else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);} catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);} }

    ??

    2 處理請(qǐng)求

    HttpServlet 提供了 doGet()、doPost() 等方法,DispatcherServlet 中這些方法是在其父類(lèi) FrameworkServlet 中實(shí)現(xiàn)的,代碼如下:

    @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); }

    這些方法又都調(diào)用了 processRequest() 方法,我們來(lái)看一下代碼:

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;// 返回與當(dāng)前線程相關(guān)聯(lián)的 LocaleContextLocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();// 根據(jù)請(qǐng)求構(gòu)建 LocaleContext,公開(kāi)請(qǐng)求的語(yǔ)言環(huán)境為當(dāng)前語(yǔ)言環(huán)境LocaleContext localeContext = buildLocaleContext(request);// 返回當(dāng)前綁定到線程的 RequestAttributesRequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();// 根據(jù)請(qǐng)求構(gòu)建ServletRequestAttributesServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);// 獲取當(dāng)前請(qǐng)求的 WebAsyncManager,如果沒(méi)有找到則創(chuàng)建WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());// 使 LocaleContext 和 requestAttributes 關(guān)聯(lián)initContextHolders(request, localeContext, requestAttributes);try {// 由 DispatcherServlet 實(shí)現(xiàn)doService(request, response);} catch (ServletException ex) {} catch (IOException ex) {} catch (Throwable ex) {} finally {// 重置 LocaleContext 和 requestAttributes,解除關(guān)聯(lián)resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}// 發(fā)布 ServletRequestHandlerEvent 事件publishRequestHandledEvent(request, startTime, failureCause);} }

    DispatcherServlet 的 doService() 方法主要是設(shè)置一些 request 屬性,并調(diào)用 doDispatch() 方法進(jìn)行請(qǐng)求分發(fā)處理,doDispatch() 方法的主要過(guò)程是通過(guò) HandlerMapping 獲取 Handler,再找到用于執(zhí)行它的 HandlerAdapter,執(zhí)行 Handler 后得到 ModelAndView ,ModelAndView 是連接“業(yè)務(wù)邏輯層”與“視圖展示層”的橋梁,接下來(lái)就要通過(guò) ModelAndView 獲得 View,再通過(guò)它的 Model 對(duì) View 進(jìn)行渲染。doDispatch() 方法如下:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;// 獲取當(dāng)前請(qǐng)求的WebAsyncManager,如果沒(méi)找到則創(chuàng)建并與請(qǐng)求關(guān)聯(lián)WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {// 檢查是否有 Multipart,有則將請(qǐng)求轉(zhuǎn)換為 Multipart 請(qǐng)求processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 遍歷所有的 HandlerMapping 找到與請(qǐng)求對(duì)應(yīng)的 Handler,并將其與一堆攔截器封裝到 HandlerExecution 對(duì)象中。mappedHandler = getHandler(processedRequest);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}// 遍歷所有的 HandlerAdapter,找到可以處理該 Handler 的 HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 處理 last-modified 請(qǐng)求頭 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;}}// 遍歷攔截器,執(zhí)行它們的 preHandle() 方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// 執(zhí)行實(shí)際的處理程序mv = ha.handle(processedRequest, response, mappedHandler.getHandler());} finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}}applyDefaultViewName(request, mv);// 遍歷攔截器,執(zhí)行它們的 postHandle() 方法mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception ex) {dispatchException = ex;}// 處理執(zhí)行結(jié)果,是一個(gè) ModelAndView 或 Exception,然后進(jìn)行渲染processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);} catch (Exception ex) {} catch (Error err) {} finally {if (asyncManager.isConcurrentHandlingStarted()) {// 遍歷攔截器,執(zhí)行它們的 afterCompletion() 方法 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}} }

    ?

    from:?https://www.cnblogs.com/tengyunhao/p/7518481.html

    總結(jié)

    以上是生活随笔為你收集整理的SpringMVC工作原理之一:DispatcherServlet的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。