springMVC请求的调用流程

springMVC请求的调用流程,第1张

根据servlet规范我们知道,当有http请求的时候,会调用到servlet中的service方法,在springMVC中会调用到DispatcherServlet中的service方法。

注:FrameworkServlet是DispatcherServlet的父类,HttpServlet是FrameworkServlet的父类

http请求最终会调到DispatcherServlet中的doDispatch方法。

在调用DispatcherServlet中的doDispatch方法之前,还有一些初始化的 *** 作:

一、URL和handler的映射收集;
二、spring容器完成启动后会发布事件;

一、URL和handle的映射收集:
AbstractHandlerMethodMapping(AbstractHandlerMethodMapping是RequestMappingHandlerMapping的父类)类实现了InitializingBean接口,所以会调到其afterPropertiesSet方法:
代码片段一:

@Override
public void afterPropertiesSet() {
	initHandlerMethods();
}

protected void initHandlerMethods() {
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	.....
}

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);
		}
	}
	//如果类上面有@Controller注解或者@RequestMapping注解
	if (beanType != null && isHandler(beanType)) {
		//建立uri和method的映射关系
		detectHandlerMethods(beanName);
	}
}

映射关系收集总结:
1、在spring容器当中获取所有的Object类,遍历循环各个类;
2、遍历循环类上所有的方法;
3、寻找有@RequestMapping注解的方法,然后注解里面的内容封装成对象RequestMappingInfo, 类上面的@RequestMapping注解也封装成对象, 然后把方法上面的注解属性结合到类上面的RequestMappingInfo对象中;
4、建立方法对象和RequestMappingInfo的映射关系,保存到methodMap这个LinkedHashMap类型中;
5、遍历LinkedHashMap,创建HandlerMethod对象,建立RequestMappingInfo和HandlerMethod对象的映射关系,建立url和RequestMappingInfo映射关系,接下来判断method上是否有CrossOrigin注解,把注解里面的属性封装成CorsConfiguration,建立handlerMethod和CorsConfiguration的映射,这个是做跨域访问控制的;

说明:
上面的代码建立好uri和method的映射关系(具体看上面的detectHandlerMethods方法),以便在后面的http请求的时候,能够在收集好的集合中根据uri找到对应的method,首先会根据url根据映射关系找到对应的RequestMappingInfo,然后根据RequestMappingInfo找到对应的HandlerMethod(handler),然后根据handler找到handlerAdapter,由handlerAdapter进行反射调用到具体方法中。

二、spring容器完成启动后会发布事件:

在FrameworkServlet中定义了一个内部类,关注了spring容器启动完成后的事件发布

所以spring容器启动完成后最终会调到DispatcherServlet中的initStrategies方法:

初始化handlerMapping和handlerAdapter会获取到WebMvcConfigurationSupport创建的HandlerMapping(用不同的方式建立URL和handler的映射,主流的handler和URL的映射还是RequestMappingHandlerMapping建立的,handler是handlerMethod,其他的handler有的是类本身,比如SimpleUrlHandlerMapping建立的映射)和HandlerAdapter,并将其分别放入handlerMappings和handlerAdapters的list集合。


那么MVC的请求在进入doDispatcher方法后:
代码片段二:

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

			//根据请求找到对应的handler
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}
			//获取跟HandlerMethod匹配的HandlerAdapter对象
			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;
				}
			}
			//前置拦截器,如果为false则直接返回
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}
			//调用到Controller具体方法
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			applyDefaultViewName(processedRequest, mv);
			//中置拦截器
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		.....
		.....
		//视图渲染
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	.....
}

doDispatch方法总结:
1、会根据url从之前收集的关系映射集合中找到对应的handler,主流的handler其实就是HandlerMethod,因为大多数都是采用注解@Controller和@RequestMapping的方式定义路径;
2、获取跟HandlerMethod匹配的HandlerAdapter对象;
3、前置拦截器的调用,如果是false则返回;
4、反射调用到Controller具体方法;
5、中置拦截器的调用
6、视图渲染,响应视图
7、后置拦截器(在processDispatchResult方法中)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/795153.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存