<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      java--Servlet以及Mvc的實現

      Servlet

      Servlet的生命周期

      Servlet 的生命周期可以分為四個步驟:

      1. 實例化。當 Web 容器(如Tomcat)啟動時,會首先加載 Servlet 類,并創建 Servlet 實例。這一過程通常在應用程序啟動時完成。

      2. 初始化。接著容器會調用 Servlet 實例的 init() 方法來進行初始化操作。在這個方法中,通常會加載并初始化與 Servlet 相關的資源,如數據庫連接池、配置文件等。

      3. 加載和處理請求。當客戶端發出請求時,容器會創建一個新的線程來處理該請求,在該線程中調用 Servlet 的 service() 方法,并將請求傳遞給它。根據不同的 HTTP 請求類型,Servlet 會調用 doGet()、doPost() 等方法來處理請求,并生成相應的響應數據。

      4. 銷毀。在 Servlet 生命周期結束時,容器會調用 destroy() 方法來銷毀 Servlet 實例,釋放相關的資源。

      注:在應用啟動的時候,web容器就會實例化初始化Servlet。但是考慮到不必要的資源消耗,提高應用程序的性能和響應速度,采用了懶加載的方式,只有在第一次請求到達后,才會實例化初始化Servlet

      Servlet接口

      1. Servlet對象主要封裝了對HTTP請求的處理, 他的運行 需要Servlet容器(Tomcat,Jetty)的支持。
      2. Servlet由Servlet容器進行管理,Servlet容器將Servlet動態加載到服務器上,與HTTP協議相關的Servlet使用HTTP請求和HTTP響應與客戶端進行交互。
      3. 如下圖,Servlet的請求首先會被HTTP服務器(如Apache)接收,HTTP服務器只負責靜態HTML界面的解析,而Servlet的請求則轉交給Servlet容器,Servlet容器會根據請求路徑以及Servlet之間的映射關系,調用相應的Servlet,Servlet將處理的結果返回給Servlet容器,并通過HTTP服務器將響應傳輸給客戶端。
      servlet容器
      Servlet 容器指的是 Web 服務器或應用服務器,如 Tomcat、Jetty、Undertow 等,它們負責管理 Servlet 的生命周期、請求處理和響應生成等工作。
      
      在 Servlet/JSP 規范中,Servlet 容器是作為 Web 容器的一部分來定義的。Web 容器是指能夠解析和執行 Web 應用程序的軟件環境,包括 Servlet 容器、JSP 引擎、Web 服務器、Java EE 應用服務器等。
      
      Servlet 容器提供了一個運行時環境,能夠加載并執行 Servlet,并提供許多 Servlet API 所需的服務,如會話管理、Cookie 處理、HTTP 請求和響應、重定向、安全認證等。Servlet 容器還提供了一些額外的服務,如 JNDI、JDBC 連接池、日志記錄、緩存等。
      
      常見的 Servlet 容器有 Tomcat、Jetty、Undertow 等。Tomcat 是 Apache 基金會下的一個 Java Servlet 容器,也是目前使用最為廣泛的 Servlet 容器之一。Jetty 和 Undertow 也是常見的 Servlet 容器,它們具有更輕量級、更快速和更靈活的特點。
      

      Servlet

      public interface Servlet {
          void init(ServletConfig var1) throws ServletException;
      
          ServletConfig getServletConfig();
      
          void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
      
          String getServletInfo();
      
          void destroy();
      }
      

      MVC請求需要的大概接口:

      Servlet的初始化

      Servlet的init方法

      當第一次請求到達后,servlet容器會調用init方法

      GenericServlet implements Servlet

      public void init(ServletConfig config) throws ServletException {
              // 保存servlet配置 供后續使用
      	this.config = config;
              // 調用init空方法,由子類實現
      	this.init();
          }
      
      public void init() throws ServletException {
      
          }
      

      HttpServlet extends GenericServlet HttpServlet沒有實現init方法

      HttpServletBean extends HttpServlet HttpServletBean 實現了init方法

      HttpServletBean是一個class直接實現了HttpServlet,這個類主要負責配置文件(web.xml)里springmvc區域的屬性操作

      @Override
      public final void init() throws ServletException {
      
      	// 通過init參數設置bean的屬性
      	PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
      	if (!pvs.isEmpty()) {
      		try {
      			BeanWrapper 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) {
      			if (logger.isErrorEnabled()) {
      				logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
      			}
      			throw ex;
      		}
      	}
              // 空方法 讓子類實現
      	initServletBean();
      }
      

      FrameworkServlet的初始化

      FrameworkServlet extends HttpServletBean 重點:重寫了initServletBean方法

      @Override
      protected final void initServletBean() throws ServletException {
      	// ......日志記錄
      	try {
                      // 初始化應用程序上下文
      		this.webApplicationContext = initWebApplicationContext();
                      // 空方法 spring 沒有實現 可自定義子類擴展
      		initFrameworkServlet();
      	}
      	catch (ServletException | RuntimeException ex) {
      		logger.error("Context initialization failed", ex);
      		throw ex;
      	}
              // ......日志記錄
      }
      
      webApplicationContext
      Web應用程序上下文是Spring提供的一個特殊的應用程序上下文,它會自動加載Web應用程序中的所有配置文件,并將所有的bean裝配到容器中。
      在這個過程中,Spring框架會掃描classpath路徑下的所有類文件,找到包含@Controller、@Service、@Repository等注解的類,并將這些類注冊為bean。
      

      initWebApplicationContext方法詳解:

      protected WebApplicationContext initWebApplicationContext() {
      	// <1> 獲得根 WebApplicationContext 對象
      	WebApplicationContext rootContext =
      			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
       
      	// <2> 獲得 WebApplicationContext wac 變量
      	WebApplicationContext wac = null;
       
      	// 第一種情況,如果構造方法已經傳入 webApplicationContext 屬性,則直接使用
      	if (this.webApplicationContext != null) {
      		wac = this.webApplicationContext;
       
      		// 如果是 ConfigurableWebApplicationContext 類型,并且未激活,則進行初始化
      		if (wac instanceof ConfigurableWebApplicationContext) {
      			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
      			if (!cwac.isActive()) { 
                                      // 未激活
      				// 設置 wac 的父 context 為 rootContext 對象
      				if (cwac.getParent() == null) {
      					cwac.setParent(rootContext);
      				}
      				// 配置和初始化 wac
      				configureAndRefreshWebApplicationContext(cwac);
      			}
      		}
      	}
       
      	// 第二種情況,從 ServletContext 獲取對應的 WebApplicationContext 對象
      	if (wac == null) {
      		wac = findWebApplicationContext();
      	}
       
      	// 第三種,創建一個 WebApplicationContext 對象
      	if (wac == null) {
      		wac = createWebApplicationContext(rootContext);
      	}
       
      	// <3> 如果未觸發刷新事件,則主動觸發刷新事件
      	if (!this.refreshEventReceived) {
      		synchronized (this.onRefreshMonitor) {
      			onRefresh(wac);
      		}
      	}
       
      	// <4> 將 context 設置到 ServletContext 中
      	if (this.publishContext) {
      		String attrName = getServletContextAttributeName();
      		getServletContext().setAttribute(attrName, wac);
      	}
       
      	return wac;
      }
      

      <1> WebApplicationContextUtils.getWebApplicationContext(getServletContext());

      ??獲取Root WebApplicationContext 對象

      public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
      	return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
      }
      
      @Nullable
      public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
      	Assert.notNull(sc, "ServletContext must not be null");
      	Object attr = sc.getAttribute(attrName);
      	if (attr == null) {
      		return null;
      	}
      	if (attr instanceof RuntimeException) {
      		throw (RuntimeException) attr;
      	}
      	if (attr instanceof Error) {
      		throw (Error) attr;
      	}
      	if (attr instanceof Exception) {
      		throw new IllegalStateException((Exception) attr);
      	}
      	if (!(attr instanceof WebApplicationContext)) {
      		throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);		}
      	return (WebApplicationContext) attr;	
      }
      

      ??而這個是在Root WebApplicationContext 容器初始化的時候進行設置的:

      ????org.springframework.web.context.ContextLoader#initWebApplicationContext

      <2> 獲得 WebApplicationContext wac 變量。下面,會分成三種情況。

      ??1.?第一種情況:如果構造方法已經注入了webApplicationContext 屬性,則直接使用

      ??????configureAndRefreshWebApplicationContext();

      protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
      	if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
      		// 如果 wac 使用了默認編號,則重新設置 id 屬性。
      		if (this.contextId != null) {
      			wac.setId(this.contextId);
      		}
      		else {
      			wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
      					ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
      		}
      	}
              // 設置 wac 的 servletContext、servletConfig、namespace 屬性。
      	wac.setServletContext(getServletContext());
      	wac.setServletConfig(getServletConfig());
      	wac.setNamespace(getNamespace());
              // 添加監聽器 SourceFilteringListener 到 wac 中.
      	wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
      
      	// 初始化屬性資源。
      	ConfigurableEnvironment env = wac.getEnvironment();
      	if (env instanceof ConfigurableWebEnvironment) {
      		((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
      	}
              // 執行處理完 WebApplicationContext 后的邏輯。目前是個空方法,暫無任何實現。
      	postProcessWebApplicationContext(wac);
              // 執行自定義初始化 context 。
      	applyInitializers(wac);
              // 刷新 wac ,從而初始化 wac 。
      	wac.refresh();
      }
      
      WebApplicationContext 子父區別
      Root WebApplicationContext 和普通的 WebApplicationContext 都是 Spring Web 應用上下文。
      
      其中,Root WebApplicationContext 是整個應用的根上下文,典型的 Web 應用只有一個根上下文,它負責加載應用中的共享 Bean,例如數據源、事務管理器、業務服務等等。而普通的 WebApplicationContext 則是針對具體的 servlet 或 Filter 而言的,它們都屬于 Root WebApplicationContext 的子上下文,負責加載特定于 servlet 或 Filter 的 Bean 定義及其他資源文件。
      
      從上下文層面來看,對于普通的 WebApplicationContext 來說,它是依賴于 Root WebApplicationContext 的,它的父級就是 Root WebApplicationContext,而 Root WebApplicationContext 沒有父級上下文。因此,對于普通的 WebApplicationContext 所加載的所有 Bean,都可以通過父級上下文 Root WebApplicationContext 獲取到。
      
      總之,Root WebApplicationContext 和普通的 WebApplicationContext 對于 Spring Web 應用的配置和管理非常重要,它們可以統一管理應用中的 Bean,并提供依賴注入、AOP 等常用功能,讓我們可以更加便捷地開發 Web 應用程序。
      

      ??2.?第二種情況:如果此處 wac 還是為空

      ??????findWebApplicationContext();

      protected WebApplicationContext findWebApplicationContext() {
              // 需要配置ContextAttribute屬性,才會去查找
      	String attrName = getContextAttribute();
      	if (attrName == null) {
      		return null;
      	}
              // 從servletContext中,獲得屬性名對應的WebApplicationContext對象
      	WebApplicationContext wac =
      			WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
      	if (wac == null) {
      		throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
      	}
      	return wac;
      }
      

      ??3.?第三種情況:如果此處 wac 還是為空,創建一個 WebApplicationContext 對象。

      ??????createWebApplicationContext(rootContext);

      protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
      	Class<?> contextClass = getContextClass();
      	if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
      		throw new ApplicationContextException(
      				"Fatal initialization error in servlet with name '" + getServletName() +
      				"': custom WebApplicationContext class [" + contextClass.getName() +
      				"] is not of type ConfigurableWebApplicationContext");
      	}
              // 創建 context 類的對象。
      	ConfigurableWebApplicationContext wac =
      			(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
              // 設置 environment、parent、configLocation 屬性。其中,configLocation 是個重要屬性。
      	wac.setEnvironment(getEnvironment());
      	wac.setParent(parent);
      	String configLocation = getContextConfigLocation();
      	if (configLocation != null) {
      		wac.setConfigLocation(configLocation);
      	}
              // 配置和初始化 wac 跟方法一中調用的同一個方法 。
      	configureAndRefreshWebApplicationContext(wac);
      
      	return wac;
      }
      

      <3> 觸發刷新機制執行onRefresh。 當 Servlet WebApplicationContext 刷新完成后,觸發 Spring MVC 組件的初始化。

      protected void onRefresh(ApplicationContext context) {
      	// For subclasses: do nothing by default.
      }
      

      這是一個空方法,具體在子類DispatcherServlet實現了。

      DispatcherServlet extends FrameworkServlet 用于HTTP請求處理程序/控制器的中央調度器

      @Override
      protected void onRefresh(ApplicationContext context) {
      	initStrategies(context);
      }
      
      /**
       * Initialize the strategy objects that this servlet uses.
       * <p>May be overridden in subclasses in order to initialize further strategy objects.
       */
      protected void initStrategies(ApplicationContext context) {
              // 文件解析器
      	initMultipartResolver(context);
      	initLocaleResolver(context);
      	initThemeResolver(context);
              // 初始化處理器映射器 
      	initHandlerMappings(context);
              // 初始化處理器適配器
      	initHandlerAdapters(context);
      	initHandlerExceptionResolvers(context);
      	initRequestToViewNameTranslator(context);
              // 視圖解析器
      	initViewResolvers(context);
      	initFlashMapManager(context);
      }
      
      // initHandlerAdapters,initHandlerMappings這兩個初始化的產生的對象將在后續處理請求時使用到
      

      <4> 如果 publishContext 為 true 時,則將 context 設置到 ServletContext 中。

      Servlet的請求處理

      Servlet的service方法

      Servlet 接口中的 service() 方法是用來處理客戶端請求的核心方法

      void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
      

      GenericServlet implements Servlet 抽象方法,未實現

      HttpServlet extends GenericServlet

      @Override
      public void service(ServletRequest req, ServletResponse res)
          throws ServletException, IOException 
      {
          HttpServletRequest  request;
          HttpServletResponse response;
              
          if (!(req instanceof HttpServletRequest &&
                  res instanceof HttpServletResponse)) {
              throw new ServletException("non-HTTP request or response");
          }
      
          // 包裝Servlet請求響應對象
          request = (HttpServletRequest) req;
          response = (HttpServletResponse) res;
      
          // 調用重載方法
          service(request, response);
      }
      
      ......
      
      protected void service(HttpServletRequest req, HttpServletResponse resp)
              throws ServletException, IOException
          {
              String method = req.getMethod();
      
              // 根據請求的方法類型 執行不同的doXxx()方法。在子類重寫這些方法,我們就能完成自己的業務需求。
              if (method.equals(METHOD_GET)) {
                  doGet(req, resp);
              } else if (method.equals(METHOD_HEAD)) {
                  doHead(req, resp);
              } else if (method.equals(METHOD_POST)) {
                  doPost(req, resp);
              } else if (method.equals(METHOD_PUT)) {
                  doPut(req, resp);
              } else if (method.equals(METHOD_DELETE)) {
                  doDelete(req, resp);
              } else if (method.equals(METHOD_OPTIONS)) {
                  doOptions(req,resp);
              } else if (method.equals(METHOD_TRACE)) {
                  doTrace(req,resp);
              } else {
                  // ......異常處理
              }
          }
      

      FrameworkServlet的service方法

      HttpServletBean extends HttpServlet HttpServletBean 沒有對service()、 doXxx()方法做處理

      FrameworkServlet extends HttpServletBean FrameworkServlet中對service()、 doXxx()方法進行了重寫

      @Override
      protected void service(HttpServletRequest request, HttpServletResponse response)
      		throws ServletException, IOException {
      
      	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
      	if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
                      // PATCH方法單獨調用processRequest
                      // 因為在父類中沒有對該類型做處理 會走異常處理 所以在這里單獨處理
      		processRequest(request, response);
      	}
      	else {
                      //   大部分情況調用父類的service方法
      		super.service(request, response);
      	}
      }
      
      PATCH 方法
      在 HTTP/1.1 標準中,PATCH 方法用于對資源進行局部更新。與 PUT 方法不同,PUT 方法用于完全替換某個 URL 所代表的資源,而 PATCH 方法則是通過對已有資源的修改來更新該資源,只更新所需修改的部分。
      
      由于 PATCH 方法比較特殊,與其他 HTTP 方法的處理方式略有不同,所以在這段代碼中單獨對 PATCH 方法進行了處理。具體來說,如果請求方法不是 PATCH 或者請求方法為 null,就調用父類的 service 方法進行處理;否則,就調用 processRequest 方法進行處理。
      
      這樣做的目的是因為 PATCH 方法相對于其他 HTTP 方法較為特殊,處理方式也比較復雜,需要進行特殊的處理。例如,在 RESTful API 設計中,PATCH 方法通常用于對一個資源進行局部更新,而且操作的粒度非常細,需要自己手動實現修改的邏輯。因此,這段代碼中將 PATCH 方法單獨處理,可以更加靈活地實現相關業務邏輯。
      

      由于父類的doXxx()都被子類實現了,所以走的子類的實現。

      @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);
      	}
      	@Override
      	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
      			throws ServletException, IOException {
      		processRequest(request, response);
      	}
      // ......所有的doXxx()方法,都會執行processRequest(request, response);
      

      processRequest(request, response); 處理此請求,無論結果如何都發布一個事件。 實際的事件處理是由抽象的doService模板方法執行的

      protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      			throws ServletException, IOException {
      
      	long startTime = System.currentTimeMillis();
              // 申明一個異常頂層對象Throwable
      	Throwable failureCause = null;
              // 本地化、國際化處理。
      	// 獲取上一個LocaleContext,這里叫上一個,是因為此方法是從ThreadLocal中獲取的,獲取當前線程的LocaleContext。
      	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
              // 構建一個本地國際化上下文,SimpleLocaleContext
      	LocaleContext localeContext = buildLocaleContext(request);
              // 獲取當前綁定到線程的RequestAttributes
      	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
              // 構建ServletRequestAttributes
      	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
      
      	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
              // 將localeContext和requestAttributes放入當前線程中
      	initContextHolders(request, localeContext, requestAttributes);
      
      	try {
                      // ***DispatcherServlet進行實現的。***
      		doService(request, response);
      	}
      	catch (ServletException | IOException ex) {
      		failureCause = ex;
      		throw ex;
      	}
      	catch (Throwable ex) {
      		failureCause = ex;
      		throw new NestedServletException("Request processing failed", ex);
      	}
      
      	finally {
      		resetContextHolders(request, previousLocaleContext, previousAttributes);
      		if (requestAttributes != null) {
      			requestAttributes.requestCompleted();
      		}
      		logResult(request, response, failureCause, asyncManager);
      		publishRequestHandledEvent(request, response, startTime, failureCause);
      	}
      }
      

      DispatcherServlet extends FrameworkServlet中央調度器中

      @Override
      protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
      	logRequest(request);
      
      	// 保留請求屬性的快照,以防出現include,
      	// 能夠在include之后恢復原始屬性。
      	Map<String, Object> attributesSnapshot = null;
      	if (WebUtils.isIncludeRequest(request)) {
      		attributesSnapshot = new HashMap<>();
      		Enumeration<?> attrNames = request.getAttributeNames();
      		while (attrNames.hasMoreElements()) {
      			String attrName = (String) attrNames.nextElement();
      			if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
      				attributesSnapshot.put(attrName, request.getAttribute(attrName));
      			}
      		}
      	}
      
      	// 向請求request中綁定 webApplication、localeResolver、themeResolver等組件
      	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());
              // 看flashMap是否為null,不為空的話做如下操作。FlashMap是用于轉發保存數據用的。
      	if (this.flashMapManager != null) {
      		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());
      		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
      	}
      		RequestPath previousRequestPath = null;
      	if (this.parseRequestPath) {
      		previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
      		ServletRequestPathUtils.parseAndCache(request);
      	}
      
      	try {
                      // ***分發處理請求***
      		doDispatch(request, response);
      	}
      	finally {
      		if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      			// Restore the original attribute snapshot, in case of an include.
      			if (attributesSnapshot != null) {
      				restoreAttributesAfterInclude(request, attributesSnapshot);
      			}
      		}
      		if (this.parseRequestPath) {
      			ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
      		}
      	}
      }
      

      doDispatch(request, response); 實際處理請求的方法

      protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
      	HttpServletRequest processedRequest = request;
      	HandlerExecutionChain mappedHandler = null;
      	boolean multipartRequestParsed = false;
      
      	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      
      	try {
      		ModelAndView mv = null;
      		Exception dispatchException = null;
      		try {
                              // 檢查當前請求是不是一個MultipartHttpServletRequest請求,(文件上傳請求)
      			processedRequest = checkMultipart(request);
      			multipartRequestParsed = (processedRequest != request);
      			// 1. 獲取處理器執行鏈(能處理請求的處理器和攔截器集合)
      			mappedHandler = getHandler(processedRequest);
      			if (mappedHandler == null) {
      				noHandlerFound(processedRequest, response);
      				return;
      			}
      			// 2. 通過處理器獲取處理器適配器
      			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      			String method = request.getMethod();
      			boolean isGet = HttpMethod.GET.matches(method);
      			if (isGet || HttpMethod.HEAD.matches(method)) {
      				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
      				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
      					return;
      				}
      			}
                              // 3. 前置攔截器執行
      			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
      				return;
      			}
      			// ***4. 反射調用方式執行控制層代碼***
      			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      			if (asyncManager.isConcurrentHandlingStarted()) {
      				return;
      			}
      			applyDefaultViewName(processedRequest, mv);
                              // 5. 后置攔截器執行
      			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);
      		}
                      // 6. 處理調度結果
      		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      	}
      	catch (Exception ex) {
      		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
      	}
      	catch (Throwable err) {
      		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);
      			}
      		}
              }
      }
      

      1、getHandler(processedRequest);

      // 返回此請求的HandlerExecutionChain。 按順序嘗試所有處理程序映射,獲取(能處理請求的處理器和攔截器集合)
      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
              // 此處的所有處理器映射器都是在init初始化的時候創建的。
      	if (this.handlerMappings != null) {
      		for (HandlerMapping mapping : this.handlerMappings) {
      			HandlerExecutionChain handler = mapping.getHandler(request);
                              // 沒有匹配上的 會返回null
      			if (handler != null) {
                                      // 優先級高的handlerMappering能處理直接返回
      				return handler;
      			}
      		}
      	}
      	return null;
      }
      

      SpringMVC六個處理器映射器的作用
      Spring MVC 中的處理器映射器(HandlerMapping)是用來將 HTTP 請求映射到具體的處理器(Handler)對象上的組件,它負責根據請求信息來確定如何處理該請求。
      
      Spring MVC 框架提供了多個不同類型的 HandlerMapping 實現,每種實現方式都有其特定的應用場景。以下是 Spring MVC 中常見的 6 種 HandlerMapping 實現及其作用:
      
        1. BeanNameUrlHandlerMapping
      BeanNameUrlHandlerMapping 將請求的 URL 映射到對應的 Bean 名稱上。例如,我們可以在 Spring 配置文件中聲明一個名為 "/hello" 的 Bean,并將它映射到 "/hello.html" 請求上,則當客戶端請求 "/hello.html" 時,就會將該請求映射到名為 "/hello" 的 Bean 上進行處理。
      
        2. ControllerClassNameHandlerMapping
      ControllerClassNameHandlerMapping 將請求的 URL 映射到對應的 Controller 類名上。例如,我們可以在 Spring 配置文件中聲明一個名為 "UserController" 的 Controller 并將它映射到 "/user/*" 請求上,這樣當客戶端請求以 "/user/" 開頭的 URL 時就會被 ControllerClassNameHandlerMapping 映射到 UserController 進行處理。
      
        3. DefaultAnnotationHandlerMapping
      DefaultAnnotationHandlerMapping 將請求的 URL 映射到帶有特定注解的處理器方法上。例如,我們可以在 Controller 類中定義一個帶有 @RequestMapping 注解的方法,并將該方法映射到 "/hello.html" 請求上,這樣當客戶端請求 "/hello.html" 時就會被 DefaultAnnotationHandlerMapping 映射到該方法進行處理。
      
        4. SimpleUrlHandlerMapping
      SimpleUrlHandlerMapping 將請求的 URL 映射到指定的處理器 Bean 上。與 BeanNameUrlHandlerMapping 類似,不同之處在于 SimpleUrlHandlerMapping 可以自定義 URL 和 Bean 的映射關系。
      
        5. AbstractDetectingUrlHandlerMapping
      AbstractDetectingUrlHandlerMapping 是一個抽象類,它提供了默認的 URL 和 Handler 映射規則,但我們也可以根據具體需求來實現自己的 URL 映射規則。
      
        6. RequestMappingHandlerMapping
      RequestMappingHandlerMapping 是 Spring MVC 中最常用的 HandlerMapping 實現,它將請求的 URL 映射到帶有 @RequestMapping 注解的方法上,并支持各種參數綁定、數據格式轉換等高級功能。
      
      以上是 Spring MVC 中常見的幾種 HandlerMapping 實現及其作用。在實際開發中,我們可以根據具體需求來選擇合適的 HandlerMapping 實現方式。
      

      mapping.getHandler(request);獲取處理器執行鏈的方法

      public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
              // 根據請求url獲取HandlerMethod
      	Object handler = getHandlerInternal(request);
      	if (handler == null) {
      		handler = getDefaultHandler();
      	}
      	if (handler == null) {
      		return null;
      	}
      	// Bean name or resolved handler?
      	if (handler instanceof String) {
      		String handlerName = (String) handler;
      		handler = obtainApplicationContext().getBean(handlerName);
      	}
      
      	// Ensure presence of cached lookupPath for interceptors and others
      	if (!ServletRequestPathUtils.hasCachedPath(request)) {
      		initLookupPath(request);
      	}
              // 獲取攔截器集合和上面獲取的HandlerMethod封裝成處理器執行鏈
      	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
      
      	if (logger.isTraceEnabled()) {
      		logger.trace("Mapped to " + handler);
      	}
      	else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
      		logger.debug("Mapped to " + executionChain.getHandler());
      	}
      	if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
      		CorsConfiguration config = getCorsConfiguration(handler, request);
      		if (getCorsConfigurationSource() != null) {
      			CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
      			config = (globalConfig != null ? globalConfig.combine(config) : config);
      		}
      		if (config != null) {
      			config.validateAllowCredentials();
      		}
      		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
      	}
      
      	return executionChain;
      }
      

      getHandlerInternal(request);根據請求url獲取HandlerMethod

      @Override
      @Nullable
      protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
              // 截取控制層形式的url
      	String lookupPath = initLookupPath(request);
              // 加鎖
      	this.mappingRegistry.acquireReadLock();
      	try {
                      // 根據url獲取HandlerMethod 
      		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
      	}
      	finally {
                      // 釋放鎖
      		this.mappingRegistry.releaseReadLock();
      	}
      }
      
      protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
      	List<Match> matches = new ArrayList<>();
      	List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
      	if (directPathMatches != null) {
                      // 尋找合適mapping
      		addMatchingMappings(directPathMatches, matches, request);
      	}
      	if (matches.isEmpty()) {
                      // 如果沒有找到 就去全部的url中遍歷
      		addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
      	}
      	if (!matches.isEmpty()) {
      		Match bestMatch = matches.get(0);
      		if (matches.size() > 1) {
                          // ......
                          // 當查詢到多個Match 則進入異常處理(正常一種類型url只有對應一個控制層方法)
      		}
                      // 請求作用域中存放HandlerMethod
      		request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
                      // 請求作用域中存放本次請求url地址
      		handleMatch(bestMatch.mapping, lookupPath, request);
      		return bestMatch.getHandlerMethod();
      	}
      	else {
      		return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
      	}
      }
      

      addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);

      private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
      	for (T mapping : mappings) {
      		T match = getMatchingMapping(mapping, request);
      		if (match != null) {
      			matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
      		}
      	}
      }
      

      getMatchMappings(mapping,request);

      1. 判斷當前 Mapping 是否支持當前請求的 HTTP 方法,如果不支持則返回 null。
      2. 將當前 Mapping 中的 URL Pattern 解析成 AntPathMatcher 對象(AntPathMatcher 是 Spring 提供的一個通配符匹配類),然后使用 AntPathMatcher 進行 URL 匹配。
      3. 如果 URL 匹配成功,則返回當前 Mapping,否則返回 null。

      需要注意的是,在進行 URL 匹配時,如果請求 URL 中包含占位符(例如{id}),則還需要做進一步的處理,將占位符所對應的值提取出來并存放到 HttpServletRequest 對象的 attribute 中,以便后面的控制器方法使用。

      2、getHandlerAdapter(mappedHandler.getHandler());

      protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
              // this.handlerAdapters 這里的四個適配器是在servlet init初始化MVC九大組件時創建的
      	if (this.handlerAdapters != null) {
      		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");
      }
      

      adaptor.supports(handler);

      具體來說,在實現 HandlerAdapter 接口的類中,通常會定義一個 supports(Object handler) 方法,并在其中對處理器對象類型進行判斷。如果當前的 HandlerAdapter 支持該類型的處理器對象,則返回 true;否則返回 false。

      例如,RequestMappingHandlerAdapter 類實現了 HandlerAdapter 接口,并且其中的 supports(Object handler) 方法用于判斷是否支持 @RequestMapping 注解標注的控制器方法。如果當前的 handler 參數是一個帶有 @RequestMapping 注解的控制器方法,則返回 true;否則返回 false。

      3、前置攔截器執行

      boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
      	for (int i = 0; i < this.interceptorList.size(); i++) {
                      // 已注冊攔截器的preHandle方法。
      		HandlerInterceptor interceptor = this.interceptorList.get(i);
                      // 順序執行所有的前置攔截器方法
      		if (!interceptor.preHandle(request, response, this.handler)) {
                              // 前置攔截器有一個返回false則執行后置攔截器方法
      			triggerAfterCompletion(request, response, null);
      			return false;
      		}
                      // 記錄當前的攔截器index 如果出現異常 后置攔截器需要從index倒敘執行
      		this.interceptorIndex = i;
      	}
              // 攔截器全部正常 程序正常執行
      	return true;
      }
      

      4、ha.handle(processedRequest, response, mappedHandler.getHandler());

      AbstractHandlerMethodAdapter類中

      @Override
      @Nullable
      public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      		throws Exception {
      	return handleInternal(request, response, (HandlerMethod) handler);
      }
      

      RequestMappingHandlerAdapter 類中

      @Override
      protected ModelAndView handleInternal(HttpServletRequest request,
      			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      	ModelAndView mav;
              // ......
              // handleInternal的核心
      	mav = invokeHandlerMethod(request, response, handlerMethod);
              // ......
      	return mav;
      }
      
      protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      
      	ServletWebRequest webRequest = new ServletWebRequest(request, response);
      	try {
      		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
      
      		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      		if (this.argumentResolvers != null) {
                              // a. 參數解析器
      			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      		}
      		if (this.returnValueHandlers != null) {
                              // b. 返回值處理器
      			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()) {
      			Object result = asyncManager.getConcurrentResult();
      			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
      			asyncManager.clearConcurrentResult();
      			LogFormatUtils.traceDebug(logger, traceOn -> {
      				String formatted = LogFormatUtils.formatValue(result, !traceOn);
      				return "Resume with async result [" + formatted + "]";
      			});
      			invocableMethod = invocableMethod.wrapConcurrentResult(result);
      		}
                      // c. 執行目標方法
      		invocableMethod.invokeAndHandle(webRequest, mavContainer);
      		if (asyncManager.isConcurrentHandlingStarted()) {
      			return null;
      		}
      
      		return getModelAndView(mavContainer, modelFactory, webRequest);
      	}
      	finally {
      		webRequest.requestCompleted();
      	}
      }
      
      a. 參數解析器argumentResolvers

      確定將要執行的目標方法的每一個參數的值是什么
      SpringMVC目標方法能寫多少種參數類型。取決于參數解析器argumentResolvers。

      this.argumentResolvers在afterPropertiesSet()方法內初始化
      RequestMappingHandlerAdapter 的 afterPropertiesSet() 方法是在 Spring 容器初始化完畢并完成依賴注入后,由 Spring 框架自動調用的一個初始化方法。

      public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
      		implements BeanFactoryAware, InitializingBean {
      	
          @Nullable
          private HandlerMethodArgumentResolverComposite argumentResolvers;
          
          @Override
          public void afterPropertiesSet() {
              ...
          	if (this.argumentResolvers == null) {//初始化argumentResolvers
              	List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
                  this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
              }
              ...
          }
       
              //初始化了一堆的實現HandlerMethodArgumentResolver接口的參數對象
      	private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
      		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
       
      		// Annotation-based argument resolution
      		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
      		resolvers.add(new RequestParamMapMethodArgumentResolver());
      		resolvers.add(new PathVariableMethodArgumentResolver());
      		resolvers.add(new PathVariableMapMethodArgumentResolver());
      		resolvers.add(new MatrixVariableMethodArgumentResolver());
      		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
      		resolvers.add(new ServletModelAttributeMethodProcessor(false));
      		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
      		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
      		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
      		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
      		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
      		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
      		resolvers.add(new SessionAttributeMethodArgumentResolver());
      		resolvers.add(new RequestAttributeMethodArgumentResolver());
       
      		// Type-based argument resolution
      		resolvers.add(new ServletRequestMethodArgumentResolver());
      		resolvers.add(new ServletResponseMethodArgumentResolver());
      		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
      		resolvers.add(new RedirectAttributesMethodArgumentResolver());
      		resolvers.add(new ModelMethodProcessor());
      		resolvers.add(new MapMethodProcessor());
      		resolvers.add(new ErrorsMethodArgumentResolver());
      		resolvers.add(new SessionStatusMethodArgumentResolver());
      		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
      		if (KotlinDetector.isKotlinPresent()) {
      			resolvers.add(new ContinuationHandlerMethodArgumentResolver());
      		}
       
      		// Custom arguments
      		if (getCustomArgumentResolvers() != null) {
      			resolvers.addAll(getCustomArgumentResolvers());
      		}
       
      		// Catch-all
      		resolvers.add(new PrincipalMethodArgumentResolver());
      		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
      		resolvers.add(new ServletModelAttributeMethodProcessor(true));
       
      		return resolvers;
      	}
          
      }
      

      參數解析器接口HandlerMethodArgumentResolver方法:

      // 用于在給定請求的上下文中將方法參數解析為參數值的策略接口
      public interface HandlerMethodArgumentResolver {
      
      	/**
      	 * 當前解析器是否支持解析這種參數
      	 */
      	boolean supportsParameter(MethodParameter parameter);
      
      	/**
      	 * 解析參數
      	 */
      	@Nullable
      	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
      
      }
      
      b. 返回值處理器returnValueHandlers

      this.returnValueHandlers在afterPropertiesSet()方法內初始化

      public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
      		implements BeanFactoryAware, InitializingBean {
      	
      	@Nullable
      	private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
          
      	@Override
      	public void afterPropertiesSet() {
       
              ...
              
      		if (this.returnValueHandlers == null) {
      			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
      		}
      	}
          
          //初始化了一堆的實現HandlerMethodReturnValueHandler接口的返回值參數對象
          private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
      		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
       
      		// Single-purpose return value types
      		handlers.add(new ModelAndViewMethodReturnValueHandler());
      		handlers.add(new ModelMethodProcessor());
      		handlers.add(new ViewMethodReturnValueHandler());
      		handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
      				this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
      		handlers.add(new StreamingResponseBodyReturnValueHandler());
      		handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
      				this.contentNegotiationManager, this.requestResponseBodyAdvice));
      		handlers.add(new HttpHeadersReturnValueHandler());
      		handlers.add(new CallableMethodReturnValueHandler());
      		handlers.add(new DeferredResultMethodReturnValueHandler());
      		handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
       
      		// Annotation-based return value types
      		handlers.add(new ServletModelAttributeMethodProcessor(false));
      		handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
      				this.contentNegotiationManager, this.requestResponseBodyAdvice));
       
      		// Multi-purpose return value types
      		handlers.add(new ViewNameMethodReturnValueHandler());
      		handlers.add(new MapMethodProcessor());
       
      		// Custom return value types
      		if (getCustomReturnValueHandlers() != null) {
      			handlers.addAll(getCustomReturnValueHandlers());
      		}
       
      		// Catch-all
      		if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
      			handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
      		}
      		else {
      			handlers.add(new ServletModelAttributeMethodProcessor(true));
      		}
       
      		return handlers;
      	}
      }
      

      HandlerMethodReturnValueHandler接口:

      // 策略接口,用于處理從處理程序方法的調用返回的值。
      public interface HandlerMethodReturnValueHandler {
      
      	/**
      	 * 當前解析器是否支持解析這種返回參數
      	 */
      	boolean supportsReturnType(MethodParameter returnType);
      
      	/**
      	 * 通過向模型添加屬性并設置視圖或將ModelAndViewContainer.setRequestHandled標志設置為true來處理給定的返回值,以指示已直接處理響應。
      	 */
      	void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
      
      }
      
      c. 執行目標方法

      invokeAndHandle方法:

      public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
       
      	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      			Object... providedArgs) throws Exception {
                      // 執行目標方法
      		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
       
              ...
              
      		try {
                              // returnValue存儲起來
      			this.returnValueHandlers.handleReturnValue(
      					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
      		}
      		catch (Exception ex) {
      			...
      		}
      	}
          
              // InvocableHandlerMethod類的,ServletInvocableHandlerMethod類繼承InvocableHandlerMethod類
              @Nullable
      	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      			Object... providedArgs) throws Exception {
       
                      // 獲取方法的參數值
      		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
       
              ...
             
      		return doInvoke(args);
      	}
       
              @Nullable
      	protected Object doInvoke(Object... args) throws Exception {
                      //@RequestMapping的方法
      		Method method = getBridgedMethod();
      		ReflectionUtils.makeAccessible(method);
      		try {
      			if (KotlinDetector.isSuspendingFunction(method)) {
      				return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
      			}
                              //通過反射調用
      			return method.invoke(getBean(), args);//getBean()指@RequestMapping的方法所在類的對象。
      		}
      		catch (IllegalArgumentException ex) {
      			...
      		}
      		catch (InvocationTargetException ex) {
      			...
      		}
      	}
          
      }   
      

      args內容:

      method內容:

      如何確定目標方法每一個參數的值
      重點分析ServletInvocableHandlerMethod的getMethodArgumentValues方法

      public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
          ...
       
      	@Nullable//InvocableHandlerMethod類的,ServletInvocableHandlerMethod類繼承InvocableHandlerMethod類
      	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      			Object... providedArgs) throws Exception {
       
                      //獲取方法的參數值
      		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
       
              ...
             
      		return doInvoke(args);
      	}
       
              //本節重點,獲取方法的參數值
      	protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      			Object... providedArgs) throws Exception {
       
      		MethodParameter[] parameters = getMethodParameters();//首先獲取方法中的所有參數
      		if (ObjectUtils.isEmpty(parameters)) {//參數為空,直接返回
      			return EMPTY_ARGS;
      		}
       
      		Object[] args = new Object[parameters.length];
      		for (int i = 0; i < parameters.length; i++) {
      			MethodParameter parameter = parameters[i];
      			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
      			args[i] = findProvidedArgument(parameter, providedArgs);
      			if (args[i] != null) {
      				continue;
      			}
                              //查看resolvers是否有支持
      			if (!this.resolvers.supportsParameter(parameter)) {
      				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
      			}
      			try {
                                      //支持的話就開始解析吧
      				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
      			}
      			catch (Exception ex) {
      				....
      			}
      		}
      		return args;
      	}
          
      }
      

      首先通過getMethodParameters方法獲取參數信息

      再通過if (!this.resolvers.supportsParameter(parameter))解析器resolvers支不支持解析該參數

         public boolean supportsParameter(MethodParameter parameter) {
             return this.getArgumentResolver(parameter) != null;
         }
      

      resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);中遍歷獲取到參數解析器

      public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
                      // 拿到 參數解析器
      		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
      		if (resolver == null) {
      			throw new IllegalArgumentException("Unsupported parameter type [" +
      					parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
      		}
                      // 開始解析
      		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
      	}
      

      resolveArgument(parameter, mavContainer, webRequest, binderFactory);中完成解析

      5、post攔截器執行

      只有前置攔截器是順序執行,post和后置都是倒序執行

      void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
      			throws Exception {
      
      		for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
      			HandlerInterceptor interceptor = this.interceptorList.get(i);
      			interceptor.postHandle(request, response, this.handler, mv);
      		}
      	}
      

      6、processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

      private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      			@Nullable Exception exception) throws Exception {
      
      		boolean errorView = false;
      
                      // 異常處理
      		if (exception != null) {
      			if (exception instanceof ModelAndViewDefiningException) {
      				logger.debug("ModelAndViewDefiningException encountered", exception);
      				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
      			}
      			else {
      				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
      				mv = processHandlerException(request, response, handler, exception);
      				errorView = (mv != null);
      			}
      		}
      
      		// Did the handler return a view to render?
      		if (mv != null && !mv.wasCleared()) {
                              // 完成視圖渲染的核心方法
      			render(mv, request, response);
      			if (errorView) {
      				WebUtils.clearErrorRequestAttributes(request);
      			}
      		}
      		else {
      			if (logger.isTraceEnabled()) {
      				logger.trace("No view rendering, null ModelAndView returned.");
      			}
      		}
      
      		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      			// Concurrent handling started during a forward
      			return;
      		}
      
      		if (mappedHandler != null) {
      			// 后置攔截器方法倒序執行
      			mappedHandler.triggerAfterCompletion(request, response, null);
      		}
      	}
      

      render(mv, request, response);
      后續處理中,會先檢查 ModelAndView 中的 View 屬性是否為空,如果為空則說明該請求需要返回 JSON 數據。接著,會遍歷已注冊的 HttpMessageConverter 列表,找到支持處理 application/json 類型的轉換器,并使用該轉換器將 ModelAndView 中的數據轉換為 JSON 格式的字符串。轉換完畢后,再通過 HttpServletResponse 將該 JSON 數據寫回到客戶端。

      posted @ 2023-05-08 12:58  嗶~嗶~嗶  閱讀(54)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲av无码牛牛影视在线二区 | 孕妇怀孕高潮潮喷视频孕妇| 久久精品无码精品免费专区| 精品久久精品久久精品九九| 日韩一区二区三区亚洲一| 亚洲αⅴ无码乱码在线观看性色 | 欧美日韩人成综合在线播放| 99久久精品国产一区二区暴力| 在线无码免费的毛片视频| 国产午夜亚洲精品不卡网站| 久久国产精品免费一区| 又爽又黄又无遮挡的激情视频| 激情五月天一区二区三区| 欧美中文字幕在线看| 综合偷自拍亚洲乱中文字幕| 成人免费无码av| 久久综合伊人77777| 日韩大片高清播放器| 欧美性群另类交| 日本中文字幕乱码免费| 一区二区三区国产偷拍| 九九re线精品视频在线观看视频 | 久久精品亚洲中文字幕无码网站| 免费人成在线视频无码| 日韩一区二区三区精品区| 午夜福利看片在线观看| 国产不卡免费一区二区| 四虎永久精品免费视频| 亚洲AV旡码高清在线观看| 又白又嫩毛又多15p| 亚洲一区二区国产av| 国产美女免费永久无遮挡| 一区二区三区午夜无码视频| 欧美午夜小视频| 里番全彩爆乳女教师| 久久国产精品色av免费看| 日本久久99成人网站| 黑人av无码一区| 国产精品一区在线蜜臀| 亚洲最大的成人网站| 亚洲AV片一区二区三区|