飞道的博客

SpringMVC 请求调用流程源码解析

308人阅读  评论(0)

前言

描述: springmvc相关文章如下:
【1】SpringMVC 入口及父子容器源码解析
【2】SpringMVC 请求调用流程源码解析

1 工程概述

1.1 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>

    <packaging>war</packaging>
    <groupId>org.example</groupId>
    <artifactId>rosh-spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.8.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!--上下文-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${
   spring.version}</version>
        </dependency>
        <!--切面-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${
   spring.version}</version>
        </dependency>
        <!--事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${
   spring.version}</version>
        </dependency>
        <!--spring-mvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${
   spring.version}</version>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${
   spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- 日志相关依赖 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.10</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>


</project>

1.2 配置文件

public class RoshWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
   
    /**
     *  父容器配置文件
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
   
        System.out.println("RoshWebInitializer invoke getRootConfigClasses");
        return new Class<?>[]{
   SpringRootConfig.class};
    }
    /**
     * 子容器配置
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
   
        System.out.println("RoshWebInitializer invoke getServletConfigClasses");
        return new Class<?>[]{
    SpringServletConfig.class};
    }
    /**
     *拦截请求(静态资源、js、css.......)
     */
    @Override
    protected String[] getServletMappings() {
   
        return new String[]{
   "/"};
    }
}


/**
 * 父容器配置文件,只扫描service
 */
@Configuration
@ComponentScan(value = "com.rosh.service")
public class SpringRootConfig {
   

}


/**
 *  子容器配置文件,仅仅扫描@Controller、@RestController
 */
@Configuration
@ComponentScan(value="com.rosh",includeFilters={
   
        @ComponentScan.Filter(type= FilterType.ANNOTATION,classes={
   Controller.class, RestController.class})
},useDefaultFilters=false)
@EnableWebMvc
public class SpringServletConfig {
   

}

1.3 service

@RestController
@RequestMapping("/hello")
public class HelloController {
   


    @Autowired
    private HelloService helloService;


    @GetMapping("")
    public String printHello() {
   

        return helloService.printHello();
    }


}

1.4 Controller

@RestController
@RequestMapping("/hello")
public class HelloController {
   


    @Autowired
    private HelloService helloService;


    @GetMapping("")
    public String printHello() {
   

        return helloService.printHello();
    }


}

1.5 启动tomcat

2 DispatcherServlet

概述: springmvc 核心类,在创建子容器时,创建DispatcherServlet,处理url请求、响应等。当web发起请求时,调用doDispatch方法。

(1) 根据request获取相应的HandlerExecutionChain(包含handlerMethod、拦截器等)
(2) 根据handlerMethod获取相应的handlerAdapter(handler方法是具体调用)
(3) 前置过滤
(4) handlerAdapter.handler()具体调用
(5) 中置过滤

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

				/**
				 *  【重点】 根据request 获取相应的HandlerExecutionChain
				 */
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
   
					noHandlerFound(processedRequest, response);
					return;
				}


				/**
				 * 根据handler获取adapter
				 */

				// Determine handler adapter for the current request.
				/**
				 * 根据handlerMethod 获取相应的 handlerAdapter
				 */
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				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;
					}
				}

				/**
				 *  前置过滤
				 */
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   
					return;
				}

				// Actually invoke the handler.
				/**
				 *  具体调用Controller 方法
				 */
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
   
					return;
				}

				applyDefaultViewName(processedRequest, mv);

				/**
				 * 中置过滤
				 */
				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);
			}
			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);
				}
			}
		}
	}

3 mappedHandler 源码解析

概念:handlerMethod 具体处理方法
     requestMappingInfo @RequestMapping相关配置

3.1 过程解析

3.1.1 handlerMapping解析

描述: handlerMapping解析,获取相应的HandlerExecutionChain

3.1.2 获取handlerMethod

描述: 根据request获取handlerMethod



描述: 根据uri获取相应的hadnlerMethod,核心方法。

@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   
		List<Match> matches = new ArrayList<>();
		/**
		 * 根据url获取mapping匹配关系
		 */
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

		//如果mapping不为空
		if (directPathMatches != null) {
   

			/**
			 * 根据mapping、request匹配相应的handlerMethod
			 */
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
   
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		/**
		 *  如果matches不为空
		 */
		if (!matches.isEmpty()) {
   

			//获取第一个方法
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
   
				Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
				matches.sort(comparator);
				bestMatch = matches.get(0);
				if (logger.isTraceEnabled()) {
   
					logger.trace(matches.size() + " matching mappings: " + matches);
				}
				if (CorsUtils.isPreFlightRequest(request)) {
   
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				/**
				 * 如果匹配多个方法,获取第二个,并且第二个和第一个一样,那么报异常
				 */
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
   
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					String uri = request.getRequestURI();
					throw new IllegalStateException(
							"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
				}
			}
			/**
			 * request设置值
			 */
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
			handleMatch(bestMatch.mapping, lookupPath, request);
			return bestMatch.handlerMethod;
		}
		else {
   
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

3.2 初始化映射关系的建立

描述: 在匹配过程中,AbstractHandlerMethodMapping.lookupHandlerMethod方法,根据uri获取requestMappingInfo、在根据requestMappingInfo获取handlerMethod,那么映射关系是如何建立的呢?


描述: 遍历所有的beanNames


描述: 如果当前类有Controller、RequestMapping注解,那么遍历所有方法,并且用getMappingForMethod进行方法匹配,如果匹配成功,创建RequestMappingInfo对象。

描述: 点进去,遍历方法,调用匿名函数进行方法匹配。

描述: 匿名匹配源码解析,带有@RequestMapping注解的方法创建RequestMappingInfo对象,并且判断该类是否带有@RequestMapping,如果带有,那么进行合并,返回RequestMappingInfo对象。

@Override
	@Nullable
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
   

		/**
		 * 带有@RequestMapping注解方法,然后注解里面的内容封装成对象
		 */
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
   

			/**
			 *  类上面的@RequestMapping注解也封装成对象
			 */
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null) {
   
				/**
				 * 把方法上面的注解属性结合到类上面的RequestMappingInfo对象中
				 */
				info = typeInfo.combine(info);
			}
			String prefix = getPathPrefix(handlerType);
			if (prefix != null) {
   
				info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
			}
		}
		return info;
	}

描述: 创建映射关系。

public void register(T mapping, Object handler, Method method) {
   
			// Assert that the handler method is not a suspending one.
			if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
   
				Class<?>[] parameterTypes = method.getParameterTypes();
				if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
   
					throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
				}
			}
			this.readWriteLock.writeLock().lock();
			try {
   
				/**
				 * 【1】 创建handlerMethod
				 */
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);

				/**
				 * 【2】 验证唯一
				 */
				validateMethodMapping(handlerMethod, mapping);

				/**
				 * 【3】创建映射,uri-> handlerMethod
				 */
				this.mappingLookup.put(mapping, handlerMethod);

				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
   

					/**
					 * 【4】 建立的是url 和 requestMappingInfo的映射
					 */
					this.urlLookup.add(url, mapping);
				}

				String name = null;
				if (getNamingStrategy() != null) {
   
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}

				/**
				 * 【5】 跨域
				 */
				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
   
					this.corsLookup.put(handlerMethod, corsConfig);
				}

				this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
			}
			finally {
   
				this.readWriteLock.writeLock().unlock();
			}
		}

3.3 总结

(1) AbstractHandlerMethodMapping 在依赖注入完成后调用afterPropertiesSet方法,会建立url->requestMappingInfo->handlerMethod的映射关系。
(2) 当请求过来时,DispatcherServlet调用doDispatch方法处理,第一步根据handMapping获取相应的HandlerExecutionChain,其核心逻辑就是根据request获取requestMappingInfo,在根据requestMappingInfo获取handlerMethod最后封装成HandlerExecutionChain对象。

4 具体调用



描述: 调用赋值

@Nullable
	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) {
   
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}

			/**
			 * 设置返回值解析器
			 */
			if (this.returnValueHandlers != null) {
   
				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);
			}

			/**
			 * 【重点】方法调用
			 */
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
   
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
   
			webRequest.requestCompleted();
		}
	}

描述: 核心调用方法






转载:https://blog.csdn.net/qq_34125999/article/details/115290357
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场