DispatcherServlet 请求处理主逻辑 : 1. 选择 Handler

本文详细解析了SpringMVC框架中DispatcherServlet如何选取适合处理请求的Handler,包括Handler的概念、来源,以及为何需要通过HandlerExecutionChain包装。同时,探讨了在未找到合适Handler时的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该系列的下一篇 : DispatcherServlet 请求处理主逻辑 : 2. 选择 Handler 对应的 HandlerAdapter

一个Handler可以理解为处理用户请求的方法。此方法可能最终对应一个开发人员定义的Controller方法,也可能是Spring MVC框架根据开发人员配置自动提供的某个方法。Handler处理请求结果一般会是一个ModelAndView对象。该对象会被接下来的步骤进行其他处理,比如根据视图名称渲染视图,进行页面调转等等。Handler处理请求过程中也可能发生异常,这些异常信息也会被后续步骤用于渲染错误页面。

DispatcherServlet处理请求时,选择Handler是根据请求找出能处理该请求的Handler的过程。该过程只负责找出能处理该请求的Handler,并不调用它处理该请求。该过程的逻辑实现是DispatcherServlet的方法HandlerExecutionChain getHandler(HttpServletRequest request)。调用是DispatcherServlet方法void doDispatch(HttpServletRequest request, HttpServletResponse response)中的语句mappedHandler = getHandler(processedRequest)。可以认为这一过程是DispatcherServlet处理请求的第一步。

应用启动过程中,根据开发人员提供的配置,DispatcherServlet组件的属性handlerMappings已经被填充,这是一个List<HandlerMapping>。根据该属性,DispatcherServlet可以根据一个请求中的信息查找能够处理它的Handler
可以将handlerMappings理解成一个查找表,保存的是<url pattern,handler 对象>对儿,当一个请求到达时,DispatcherServlet会获取该请求的请求路径,从该查找表中查找到相应的Handler。比如对于一个映射到Controller方法上的请求,这里的Handler其实是一个HandlerMethod

参考文章 : Spring MVC : WebMvcConfigurationSupport 中定义的 HandlerMapping 组件

getHandler方法正是使用了handlerMappings查找到达请求的handler的 ,代码逻辑如下所示 :

	/**
	 * Return the HandlerExecutionChain for this request.
	 * Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or null if no handler could be found
	 */
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

如上所示,方法getHandler的逻辑简单直白,就是遍历handlerMappings中每个HandlerMapping以查找能处理指定请求的Handler,如果找到了合适的Handler,则包装成HandlerExecutionChain形式返回。如果没有找到,则返回null

这里为什么要包装成HandlerExecutionChain,而不是直接返回Handler本身呢?这是因为Spring MVC的拦截器机制有可能需要向目标Handler包裹一些HandlerInterceptor。常见的一些HandlerInterceptorConversionServiceExposingInterceptor,ResourceUrlProviderExposingInterceptor

DispatcherServlet#doDispatch使用getHandler找不到处理当前请求的handler是,会怎么做呢 ?

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

从上面代码可见,这种情况下DispatcherServlet#doDispatch会调用方法noHandlerFound,然后就直接返回了,不再继续下面的其他步骤。方法noHandlerFound的实现逻辑如下 :

	/**
	 * No handler found -> set appropriate HTTP response status.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception if preparing the response failed
	 */
	protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (pageNotFoundLogger.isWarnEnabled()) {
			pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
		}
		if (this.throwExceptionIfNoHandlerFound) {
          // 如果属性 throwExceptionIfNoHandlerFound 为 true,则抛出异常 NoHandlerFoundException
			throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
					new ServletServerHttpRequest(request).getHeaders());
		}
		else {
           // 如果属性 throwExceptionIfNoHandlerFound 为 false , 则 response.sendError(404)
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
		}
	}

从以上代码可见,根据开发人员提供的配置this.throwExceptionIfNoHandlerFound的不同,noHandlerFound会抛出异常NoHandlerFoundException或者向响应发送错误404。缺省情况下,this.throwExceptionIfNoHandlerFoundfalse

总结

  • 本文梳理了DispatcherServlet针对到达的请求获取能处理该请求的Handler的过程,包含如下要点 :
    • Handler是什么 ?
    • 这些Handler从哪里来 ?
    • Handler为什么要用HandlerExecutionChain形式包装?
    • 如何判断一个Handler是否支持处理某个请求 ?
    • 如果找不到能处理该请求的Handler会怎么样 ?

相关文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值