0
点赞
收藏
分享

微信扫一扫

三、Spring MVC请求流程及源码分析

晒大太阳了 2022-03-12 阅读 61

今天的天气有点阴,但是丝毫不影响帅气的我,闪亮登场,哈哈…
这回简单看看Spring MVC请求流程及源码分析。

一、简述Spring MVC启动流程

1、请求发送到DispatcherServlet

2、 DispatcherServlet收到请求,调用处理器映射器HandlerMapping。处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。

3、DispatcherServlet根据处理器Handler获取处理器适配器 HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作

4、执行拦截器前置方法

5、执行处理器Handler(Controller)的业务方法,Handler执行完成返回ModelAndView到DispatcherServlet。

6、执行拦截器后置方法

7、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover解析后返回具体View

7、 DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。

8、DispatcherServlet响应用户。

画了一个简易流程图:

在这里插入图片描述

二、源码分析

前端发出请求,会调用Servlet的service方法。我们注册了DispatcherServlet拦截所有请求。

看下DispatcherServlet继承图:
在这里插入图片描述

debug调试下代码:

在这里插入图片描述
核心方法就是doDispatch(request, response)方法。去掉非核心代码

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

    ...
	HandlerExecutionChain mappedHandler = null;
	//1、通过HandlerMapping获得HandlerExecutionChain处理器执行链(handler和拦截器)
	mappedHandler = getHandler(processedRequest);
	//2、根据handler处理获得对应的HandlerAdapter处理器适配器
	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	//3、执行拦截器的applyPreHandle前置方法
	if (!mappedHandler.applyPreHandle(processedRequest, response)) {
		return;
	}
    //4、执行handler处理器方法,也就是执行我们后端业务方法,返回ModelAndView
	mappedHandler.getHandler());
	//5、执行拦截器的applyPostHandle后置方法
    mappedHandler.applyPostHandle(processedRequest, response, mv);
    //6、处理结果,ViewReslover视图解析器解析,View渲染
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	...
}

请求流程的核心代码就这么多,哈哈…是不是很easy~

下面我们看下getHandler方法,通过HandlerMapping获得HandlerExecutionChain处理器执行链(handler和拦截器)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
		    //调用HandlerMapping的getHandler方法,获得HandlerExecutionChain,不为空,则返回
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

获得多个HandlerMapping,按照order排好序的,按序调用,返回的HandlerExecutionChain不为空,就返回。
在这里插入图片描述

下面看看第一个RequestMappingHandlerMapping,代码调试下,先看

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获取handler
		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
		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 (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
			CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			config = (config != null ? config.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}

getHandlerInternal方法,先获得请求路径,然后寻找HandlerMethod。

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //request中获得请求路径
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	request.setAttribute(LOOKUP_PATH, lookupPath);
	//加读锁
	this.mappingRegistry.acquireReadLock();
	try {
	    //寻找HandlerMethod,即找到对应的controller和方法
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
	    //释放锁
		this.mappingRegistry.releaseReadLock();
	}
}

lookupHandlerMethod方法,找到HandlerMethod,匹配到要controller和方法。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List<Match> matches = new ArrayList<>();
	//mappingRegistry的urlLookup的中找,返回RequestMappingInfo信息,直接匹配路径,比如请求:“/hello”
	List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	if (directPathMatches != null) {
	    //匹配请求方式,参数,headers等,就是各种condition的getMatchingCondition
		addMatchingMappings(directPathMatches, matches, request);
	}
	if (matches.isEmpty()) {
		//路径直接匹配不到的候,拿所有的RequestMappingInfo信息去匹配。如"/hello/{xxx}"
		addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
	}

    //多个匹配排序,选择最优的RequestMappingInfo
	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.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
		//处理匹配的uri模板变量等,比如 后端:/hello/{xxx}  请求是:"/hello/111",得到xxx = 111 
		handleMatch(bestMatch.mapping, lookupPath, request);
		//放回handlerMethod,包含contoller和方法等信息
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
	}
}


再看下 getHandlerExecutionChain(handler, request)创建HandlerExecutionChain ,添加拦截器

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    //创建HandlerExecutionChain ,设置拦截器
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

到此我们大致看了下这个根据请求寻找后端方法的代码流程。匹配细节就不展开啦。

下面我们看下Spring MVC是如何注册组件的?

@EnableWebMvc注解import了DelegatingWebMvcConfiguration

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

DelegatingWebMvcConfiguration继承WebMvcConfigurationSupport,在父类中以@Bean的形式注入了相关组件
在这里插入图片描述
那么我们还有一个疑惑,MappingRegistry是何时初始化的?
看下这个继承图:
在这里插入图片描述
这样上步注入RequestMappingHandlerMapping时,会调用afterPropertiesSet方法。

public void afterPropertiesSet() {
	initHandlerMethods();
}

initHandlerMethods初始化HandlerMethod

protected void initHandlerMethods() {
    //获取所有Object
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
		   //处理候选类
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

processCandidateBean方法

protected void processCandidateBean(String beanName) {
	Class<?> beanType = null;
	try {
		beanType = obtainApplicationContext().getType(beanName);
	}
	catch (Throwable ex) {
		// An unresolvable bean type, probably from a lazy bean - let's ignore it.
		if (logger.isTraceEnabled()) {
			logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
		}
	}
	// 看看是不是handler
	if (beanType != null && isHandler(beanType)) {
	    //获取HandlerMethods,注册
		detectHandlerMethods(beanName);
	}
}

isHandler方法,判断是不是handler,包含Controller和RequestMapping注解的bean

@Override
protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

detectHandlerMethods方法:

protected void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
					    //创建RequestMappingInfo
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			//遍历,注册
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

registerHandlerMethod方法注册HandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}

public void register(T mapping, Object handler, Method method) {
	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 {
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		validateMethodMapping(handlerMethod, mapping);
		//所有uri
		this.mappingLookup.put(mapping, handlerMethod);
        //直接的uri,不包含 "/hello/{xxx}" 这种
		List<String> directUrls = getDirectUrls(mapping);
		for (String url : directUrls) {
			this.urlLookup.add(url, mapping);
		}

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

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

到此,我们看了主要逻辑,工程启动时注入RequestMappingHandlerMapping,初始化后,生成MappingRegistry,管理所有的url和handlerMethod的关系。

举报

相关推荐

0 条评论