SpringMVC的流程

(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。

SpringMVC如何找到请求的目标控制器方法?

Spring MVC Web应用开发时,我们会开发出相应的 controller class/method, 关联到相应的url,然后用户在访问系统时,输入正确的url,相应的controller class/method 就会被执行,返回给用户相应的处理结果。那么Spring MVC Web应用内部是如何找到一个请求对应的controller class/method方法呢 ? 本文基于源代码回答此问题。

简单地讲,应用在启动的时候,Spring MVC将配置文件或者通过注解@Controller+@RequestMapping定义的<url,controller class/method>映射关系搜集起来,保存在内存中,然后在请求到达时,根据请求的url(实际上也会使用相应的HTTP method)就能找到相应的 controller class/method 。下面我们分成这两步进行分析。

初始化handlerMappings

DispatcherServlet有一个属性handlerMappings,用于在内存中保持配置定义的<url,controller class/method>映射关系。在DispatcherServlet初始化的过程中,该属性会根据配置信息被填充正确的信息。

private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;

	// detectAllHandlerMappings 表示是否要从上下文中检测所有的 handlerMappings,缺省值为 true
	if (this.detectAllHandlerMappings) {
		// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
		// 从 ApplicationContext 及其祖先级别上下文中找出所有类型为 HandlerMapping 的 bean ,
		// 这些 bean 实在 bean 扫描阶段根据配置或者注解进入到 Spring IoC 容器的。
		Map<String, HandlerMapping> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			// 对搜集到的 handlerMappings 进行排序
			AnnotationAwareOrderComparator.sort(this.handlerMappings);
		}
	}
	else {
		try {
			HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
			this.handlerMappings = Collections.singletonList(hm);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default HandlerMapping later.
		}
	}

	// Ensure we have at least one HandlerMapping, by registering
	// a default HandlerMapping if no other mappings are found.
	if (this.handlerMappings == null) {
		this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		if (logger.isDebugEnabled()) {
			logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
		}
	}
}

找到当前请求的handler

每个请求到达DispatcherServlet被处理时都会使用其方法protected void doDispatch(HttpServletRequest request, HttpServletResponse response)。该方法调用getHandler()来获取当前请求的handler。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 遍历所有的 handlerMappings , 找到第一个支持当前请求 request 的那一个并返回一个 HandlerExecutionChain
	// 对象,注意这里是 HandlerExecutionChain 对象,而不是一个什么 handler 对象,
	// 一个 HandlerExecutionChain 的内容是 1 handler + N handler interceptors , 包含了相应的 handler 对象
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}		
		// 如果当前 HandlerMapping hm 支持当前 request, 那就直接使用它;
		// 如果当前 HandlerMapping hm 不支持当前 request, 其 getHandler 方法会返回 null;
		// getHandler 内部会获取 request 的 url 信息 , http method 信息,然后判断自己是否支持该 request,
		// 具体的实现逻辑不同的HandlerMapping实现类会有不同。
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	// 如果没有所有配置的 handlerMappings  都不支持该请求,则返回 null,
	// 此时DispatcherServlet会抛出一个异常NoHandlerFoundException或者向客户端返回一个404,
	// 具体怎么做看开关的设置,缺省是会向客户端返回一个404。
	return null;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值