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

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

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

      1. Java SpringMVC框架源碼分析

      目錄

      1. 使用

      1.1. 新建項目

      1.1.1. 第一種方式

      1.1.1.1. 新建web項目

      1.1.1.2. 導入jar包依賴

      在WEB-INF下新建lib目錄,導入如下依賴。并且add as library

      1.1.2. 第二種方式

      1.1.2.1. 新建maven工程

      1.1.2.2. 添加web框架支持


      1.1.2.3. maven pom 依賴

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.zsk</groupId>
          <artifactId>springmvc_test</artifactId>
          <version>1.0-SNAPSHOT</version>
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <java.version>1.8</java.version>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
          </properties>
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.1.8.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>jstl</artifactId>
                  <version>1.2</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet.jsp</groupId>
                  <artifactId>javax.servlet.jsp-api</artifactId>
                  <version>2.3.3</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>javax.servlet-api</artifactId>
                  <version>4.0.1</version>
                  <scope>provided</scope>
              </dependency>
          </dependencies>
      
      
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <version>3.7.0</version>
                  </plugin>
              </plugins>
              <!--配置資源目錄-->
              <resources>
                  <resource>
                      <directory>src/main/java</directory>
                      <includes>
                          <include>**/*.*</include>
                      </includes>
                  </resource>
                  <resource>
                      <directory>src/main/resources</directory>
                      <includes>
                          <include>**/*.*</include>
                      </includes>
                  </resource>
                  <!-- 打包時將jsp文件拷貝到META-INF目錄下 -->
                  <resource>
                      <!-- 指定resources插件處理哪個目錄下的資源文件 -->
                      <directory>src/main/webapp</directory>
                      <!--注意此次必須要放在此目錄下才能被訪問到 -->
                      <targetPath>META-INF/resources</targetPath>
                      <includes>
                          <include>**/*.*</include>
                      </includes>
                      <filtering>false</filtering>
                  </resource>
              </resources>
          </build>
      
      </project>
      

      1.1.2.4. 修改project配置lib包

      1.2. 配置spring mvc

      • WEB-INF/web.xml
        配置DispatcherServlet和springmvc.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
          <servlet>
              <servlet-name>dispatcherServlet</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>springmvc.xml</param-value>
              </init-param>
              <load-on-startup>1</load-on-startup>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
      • springmvc.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:p="http://www.springframework.org/schema/p"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
      
          <context:component-scan base-package="com.zsk.controller"/>
      
          <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
              <property name="prefix" value="/WEB-INF/jsp/"/>
              <property name="suffix" value=".jsp"/>
          </bean>
      
          <!--尋找RequestMapping-->
          <mvc:annotation-driven/>
          <!--尋找靜態資源-->
          <mvc:default-servlet-handler/>
      </beans>
      

      1.3. 新建controller

      • com.zsk.controller.TestController
      package com.zsk.controller;
      
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      /**
       * @description:
       * @author: zsk
       * @create: 2019-11-27 23:43
       **/
      @Controller
      public class TestController
      {
          @RequestMapping("/test")
          public String test()
          {
              return "test";
          }
      }
      
      
      • com.zsk.controller.TestController2
      package com.zsk.controller;
      
      import org.springframework.stereotype.Component;
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.web.servlet.mvc.Controller;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      /**
       * @description:
       * @author: zsk
       * @create: 2019-11-30 21:28
       **/
      @Component("/test2")
      public class TestController2 implements Controller
      {
          @Override
          public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception
          {
              ModelAndView test2 = new ModelAndView("test2");
              return test2;
          }
      }
      
      

      1.4. 新建jsp

      • WEB-INF/jsp/test.jsp
      <%--
         
        User: zsk
        Date: 2019/11/29
        Time: 20:45
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
        <head>
          <title>Test</title>
        </head>
        <body>
        Hello World
        </body>
      </html>
      
      
      • WEB-INF/jsp/test2.jsp
      <%--
         
        User: zsk
        Date: 2019/11/27
        Time: 23:24
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
        <head>
          <title>Test2</title>
        </head>
        <body>
        Hello2
        </body>
      </html>
      
      

      1.5. 新建html文件

      • web/abc.html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>abc</title>
      </head>
      <body>
      abc
      </body>
      </html>
      

      1.6. 配置tomcat


      1.7. 項目結構

      • 第一種
      • 第二種

      1.8. 啟動并訪問


      2. 源碼分析

      2.1. 打斷點

      我們在com.zsk.controller.TestController#test的方法上打上斷點,查看調用棧如下

      test:17, TestController (com.zsk.controller)
      invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
      invoke:62, NativeMethodAccessorImpl (sun.reflect)
      invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
      invoke:498, Method (java.lang.reflect)
      doInvoke:190, InvocableHandlerMethod (org.springframework.web.method.support)
      invokeForRequest:138, InvocableHandlerMethod (org.springframework.web.method.support)
      invokeAndHandle:104, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
      invokeHandlerMethod:892, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
      handleInternal:797, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
      handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
      
      doDispatch:1039, DispatcherServlet (org.springframework.web.servlet)
      doService:942, DispatcherServlet (org.springframework.web.servlet)
      processRequest:1005, FrameworkServlet (org.springframework.web.servlet)
      doGet:897, FrameworkServlet (org.springframework.web.servlet)
      service:634, HttpServlet (javax.servlet.http)
      service:882, FrameworkServlet (org.springframework.web.servlet)
      service:741, HttpServlet (javax.servlet.http)
      
      internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
      doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
      doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
      internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
      doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
      invoke:199, StandardWrapperValve (org.apache.catalina.core)
      invoke:96, StandardContextValve (org.apache.catalina.core)
      invoke:528, AuthenticatorBase (org.apache.catalina.authenticator)
      invoke:139, StandardHostValve (org.apache.catalina.core)
      invoke:81, ErrorReportValve (org.apache.catalina.valves)
      invoke:678, AbstractAccessLogValve (org.apache.catalina.valves)
      invoke:87, StandardEngineValve (org.apache.catalina.core)
      service:343, CoyoteAdapter (org.apache.catalina.connector)
      service:609, Http11Processor (org.apache.coyote.http11)
      process:65, AbstractProcessorLight (org.apache.coyote)
      process:810, AbstractProtocol$ConnectionHandler (org.apache.coyote)
      doRun:1506, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
      run:49, SocketProcessorBase (org.apache.tomcat.util.net)
      runWorker:1149, ThreadPoolExecutor (java.util.concurrent)
      run:624, ThreadPoolExecutor$Worker (java.util.concurrent)
      run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
      run:748, Thread (java.lang)
      

      從中間一段調用棧看出主要經過HttpServletFrameworkServletDispatcherServlet這幾個類的方法,我們從搞清楚這幾個類的關系

      2.2. servlet類圖


      由圖可以看出這幾類都是servlet,我們記得servlet的生命周期Servlet.md
      所以從HttpServlet的service方法開始追蹤源碼

      2.3. DispatcherServlet是怎么加載的

      • 如果是web.xml配置的
        這是我們自己在web.xml中配置的,在tomcat啟動的時候會加載<load-on-startup>1</load-on-startup>的Servlet,同時傳入<init-param></init-param>的參數

      • 如果是servlet3.0的配置方式

      2.4. 關鍵方法是哪個

      2.4.1. HttpServlet service

      @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");
          }
      
          request = (HttpServletRequest) req;
          response = (HttpServletResponse) res;
      
      	//只是將request、resposne對象封裝成HttpServletRequest和HttpServletResponse
      	//調用子類的方法
      	//org.springframework.web.servlet.FrameworkServlet#service
          service(request, response);
      }
      

      2.4.2. FrameworkServlet service

      protected void service(HttpServletRequest request, HttpServletResponse response)
      		throws ServletException, IOException {
      
      	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
      	if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
      		processRequest(request, response);
      	}
      	else {
      		//調用父類的另一個service方法
      		//javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
      		super.service(request, response);
      	}
      
      }
      
      

      2.4.3. HttpServlet 另一個service

       protected void service(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException
      {
          String method = req.getMethod();
      
      	//根據http方法調用doXXX方法
          if (method.equals(METHOD_GET)) {
              long lastModified = getLastModified(req);
              if (lastModified == -1) {
                  // servlet doesn't support if-modified-since, no reason
                  // to go through further expensive logic
                  //get方法
              	//org.springframework.web.servlet.FrameworkServlet#doGet
                  doGet(req, resp);
              } else {
                  long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                  if (ifModifiedSince < lastModified) {
                      // If the servlet mod time is later, call doGet()
                      // Round down to the nearest second for a proper compare
                      // A ifModifiedSince of -1 will always be less
                      maybeSetLastModified(resp, lastModified);
                      doGet(req, resp);
                  } else {
                      resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                  }
              }
      
          } else if (method.equals(METHOD_HEAD)) {
              long lastModified = getLastModified(req);
              maybeSetLastModified(resp, lastModified);
              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 {
              //
              // Note that this means NO servlet supports whatever
              // method was requested, anywhere on this server.
              //
      
              String errMsg = lStrings.getString("http.method_not_implemented");
              Object[] errArgs = new Object[1];
              errArgs[0] = method;
              errMsg = MessageFormat.format(errMsg, errArgs);
              
              resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
          }
      }
      
      

      2.4.4. FrameworkServlet doGet

      protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      		throws ServletException, IOException {
      	//調用FrameworkServlet#processRequest
      	processRequest(request, response);
      }
      
      

      2.4.5. FrameworkServlet processRequest

      protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      		throws ServletException, IOException {
      
      //...
      
      	try {
      	//調用DispatcherServlet#doService
      		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);
      	}
      }
      

      2.4.6. DispatcherServlet doService

      protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
      	//...
      	try {
      	    //調用DispatcherServlet#doDispatch
      		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);
      			}
      		}
      	}
      }
      

      2.4.7. DispatcherServlet doDispatch【關鍵】

      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 {
      				//處理文件二進制流的請求
      				processedRequest = checkMultipart(request);
      				multipartRequestParsed = (processedRequest != request);
      
      
      				//1.獲取相應的HandlerExecutionChain【包括handler和interceptor】處理請求
      				//handler是我們自己的處理類
      				//intercepter是攔截器
      				mappedHandler = getHandler(processedRequest);
      				//沒找到handler,那么控制臺打印not found,跳轉到404
      				if (mappedHandler == null) {
      					noHandlerFound(processedRequest, response);
      					return;
      				}
      
      
      				//2.將Handler封裝成HandlerAdapter【adpater的作用是適配不同的handler
      				//比如有@Controller、implement Controller、implement RequestHandler等】
      				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      
      
      				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;
      					}
      				}
      				//3.調用interceptor的preHandle處理
      				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
      					return;
      				}
      
      				//4.真正調用handler的方法
      				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      
      				if (asyncManager.isConcurrentHandlingStarted()) {
      					return;
      				}
      
      				applyDefaultViewName(processedRequest, mv);
      				//5.調用interceptor的postHandle處理
      				mappedHandler.applyPostHandle(processedRequest, response, mv);
      			}
      			catch (Exception ex) {
      				dispatchException = ex;
      			}
      			catch (Throwable err) {
      				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()) {
      				if (mappedHandler != null) {
      					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      				}
      			}
      			else {
      				if (multipartRequestParsed) {
      					cleanupMultipart(processedRequest);
      				}
      			}
      		}
      	}
      
      

      2.5. Handler是怎么找到的

      2.5.1. 獲取所有HandlerMapping一個個試

      • getHandler
      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      	//查找合適的HandlerExecutionChain【包括handler和interceptor】
      	if (this.handlerMappings != null) {
      		//不同的Handler有不同的HandlerMapping處理
      			//如果是xml配置或者implements Controller的那么使用BeanNameUrlHandlerMapping
      			//如果是注解@Controller配置的那么使用RequestMappingHandlerMapping
      			//如果是靜態資源映射且開啟了<mvc:default-servlet-handler/>,使用的是SimpleUrlHandlerMapping
      		//HandlerMapping已經提前定義好了:C:/Users/zsk/.m2/repository/org/springframework/spring-webmvc/5.1.8.RELEASE/spring-webmvc-5.1.8.RELEASE.jar!/org/springframework/web/servlet/DispatcherServlet.properties
      		for (HandlerMappig mapping : this.handlerMappings) {
      			//只要找到一個能處理的就返回
      			HandlerExecutionChain handler = mapping.getHandler(request);
      			if (handler != null) {
      				return handler;
      			}
      		}
      	}
      	return null;
      }
      

      2.5.1.1. HandlerMapping類型

      2.5.1.1.1. 如果是xml配置或者implements Controller的那么使用BeanNameUrlHandlerMapping
      2.5.1.1.2. 如果是注解@Controller配置的那么使用RequestMappingHandlerMapping
      2.5.1.1.3. 如果是靜態資源映射且開啟了mvc:default-servlet-handler/,使用的是SimpleUrlHandlerMapping

      2.5.1.2. 通過HandlerMapping獲取Handler和攔截器鏈

      • AbstractHandlerMapping#getHandler
      @Override
      @Nullable
      public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      	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);
      	}
      
      	//加上攔截器
      	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
      
      	if (logger.isTraceEnabled()) {
      		logger.trace("Mapped to " + handler);
      	}
      	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      		logger.debug("Mapped to " + executionChain.getHandler());
      	}
      
      	if (CorsUtils.isCorsRequest(request)) {
      		CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
      		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
      	}
      
      	return executionChain;
      }
      
      2.5.1.2.1. 拿到url對應的Handler
      • AbstractHandlerMethodMapping#getHandlerInternal
      protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
      	//拿到url路徑
      	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
      	this.mappingRegistry.acquireReadLock();
      	try {
      		//通過url路徑從map中查找
      		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
      	}
      	finally {
      		this.mappingRegistry.releaseReadLock();
      	}
      }
      

      2.6. Handler Adapter是怎么適配的

      2.6.1. 遍歷所有HandlerMappingAdapter一個個試

      • getHandlerAdapter
      protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
      	//如果是注解@Controller配置的那么使用RequestMappingHandlerMappingAdapter【AbstractHandlerMethodAdapter】
      	//如果是靜態資源或者implements Controller使用的是SimpleControllerHandlerAdapter
      	//如果是implements HttpRequestHandler那么HttpRequestHandlerAdapter
      	//如果是Servlet那么SimpleServletHandlerAdapter
      	if (this.handlerAdapters != null) {
      		for (HandlerAdapter adapter : this.handlerAdapters) {
      			//適配器是否匹配當前handler
      			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");
      }
      

      2.6.1.1. HandlerAdapter類型

      2.6.1.1.1. 如果是靜態資源或者implements Controller使用的是SimpleControllerHandlerAdapter
      • SimpleControllerHandlerAdapter#supports
      public boolean supports(Object handler) {
      	return (handler instanceof Controller);
      }
      
      2.6.1.1.2. 如果是implements HttpRequestHandler那么HttpRequestHandlerAdapter
      • HttpRequestHandlerAdapter#supports
      public boolean supports(Object handler) {
      	return (handler instanceof HttpRequestHandler);
      }
      
      2.6.1.1.3. 如果是Servlet那么SimpleServletHandlerAdapter
      • SimpleServletHandlerAdapter#supports
      public boolean supports(Object handler) {
      	return (handler instanceof Servlet);
      }
      
      2.6.1.1.4. 如果是注解@Controller配置的那么使用RequestMappingHandlerMappingAdapter
      • AbstractHandlerMethodAdapter#supports
      public final boolean supports(Object handler) {
      	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
      }
      

      2.7. handler的方法是怎么調用的

      2.7.1. 如果是implements Controller的強轉直接調用

      public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      		throws Exception {
      	//強轉直接調用
      	return ((Controller) handler).handleRequest(request, response);
      }
      

      2.7.2. @Controller的反射調用

      public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      		throws Exception {
      
      	return handleInternal(request, response, (HandlerMethod) handler);
      }
      
      protected ModelAndView handleInternal(HttpServletRequest request,
      		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      
      	ModelAndView mav;
      	//這個
      	mav = invokeHandlerMethod(request, response, handlerMethod);
      	return mav;
      }
      
      protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      	//這個
      	invocableMethod.invokeAndHandle(webRequest, mavContainer);
      }
      
      
      public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      		Object... providedArgs) throws Exception {
      	//這個
      	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
      }
      
      public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      		Object... providedArgs) throws Exception {
      	//解析調用參數
      	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
      	if (logger.isTraceEnabled()) {
      		logger.trace("Arguments: " + Arrays.toString(args));
      	}
      	//反射調用
      	return doInvoke(args);
      }
      

      2.8. 視圖是怎么渲染的

      • processDispatchResult
      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()) {
      		//渲染handler返回的ModelAndView
      		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);
      	}
      }
      
      

      2.8.1. 獲取合適的view并渲染

      • DispatcherServlet#render
      protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
      	// Determine locale for request and apply it to the response.
      	Locale locale =
      			(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
      	response.setLocale(locale);
      
      	View view;
      	String viewName = mv.getViewName();
      	if (viewName != null) {
      		// We need to resolve the view name.
      		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
      		if (view == null) {
      			throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
      					"' in servlet with name '" + getServletName() + "'");
      		}
      	}
      	else {
      		// No need to lookup: the ModelAndView object contains the actual View object.
      		//通過視圖名和ViewResolver獲取相應的view
      		view = mv.getView();
      		if (view == null) {
      			throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
      					"View object in servlet with name '" + getServletName() + "'");
      		}
      	}
      
      	// Delegate to the View object for rendering.
      	if (logger.isTraceEnabled()) {
      		logger.trace("Rendering view [" + view + "] ");
      	}
      	try {
      		if (mv.getStatus() != null) {
      			response.setStatus(mv.getStatus().value());
      		}
      		//使用view渲染
      		view.render(mv.getModelInternal(), request, response);
      	}
      	catch (Exception ex) {
      		if (logger.isDebugEnabled()) {
      			logger.debug("Error rendering view [" + view + "]", ex);
      		}
      		throw ex;
      	}
      }
      
      protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
      		Locale locale, HttpServletRequest request) throws Exception {
      
      	if (this.viewResolvers != null) {
      		//通過視圖解析器獲取的
      		for (ViewResolver viewResolver : this.viewResolvers) {
      			View view = viewResolver.resolveViewName(viewName, locale);
      			if (view != null) {
      				return view;
      			}
      		}
      	}
      	return null;
      }
      

      3. 參考

      posted @ 2025-07-06 11:39  ThinkerQAQ  閱讀(12)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲理论在线A中文字幕| 亚洲v国产v天堂a无码二区| 日本高清视频网站www| 中文字幕日韩国产精品| 亚洲欧美偷国产日韩| 亚洲一区二区三区啪啪| 国产一区| 日韩在线视频一区二区三区| 最新午夜男女福利片视频| 久久天堂无码av网站| 一区二区三区四区激情视频| 国产精品久久久久鬼色| 国产日女人视频在线观看| 精品国产高清中文字幕| 亚洲有无码中文网| 好吊视频一区二区三区| 中文字幕av高清片| 中文字幕一区二区三区精华液| 国产成人综合网亚洲第一| 亚洲毛片多多影院| 色欲狠狠躁天天躁无码中文字幕 | 性动态图无遮挡试看30秒| 亚洲欧洲日韩国内高清| 国产熟睡乱子伦视频在线播放| 久久无码中文字幕免费影院| 久久久午夜精品福利内容| 啊轻点灬大JI巴太粗太长了在线| 久久亚洲国产欧洲精品一| 天天干天天色综合网| 洛扎县| 亚洲啪啪精品一区二区的| 无码人妻aⅴ一区二区三区蜜桃| 免费可以在线看a∨网站| 欧美性猛交xxxx免费看| 在线观看精品日本一区二| 精品久久久无码人妻中文字幕| 中文 在线 日韩 亚洲 欧美| 猫咪AV成人永久网站在线观看| 欧美在线人视频在线观看| 双乳奶水饱满少妇呻吟免费看| 激情在线网|