Spring MVC 源码分析之 DispatcherServlet#getHandlerAdapter 方法

前言:

前面我们分析了 Spring MVC 的工作流程源码,其核心是 DispatcherServlet#doDispatch 方法,我们前面分析了获取 Handler 的方法 DispatcherServlet#getHandler 方法,本篇我们重点分析一下获取当前请求的适配器 HandlerAdapter 的实现原理,具体方法入口是 DispatcherServlet#getHandlerAdapter。

Spring MVC 知识传送门:

详解 Spring MVC(Spring MVC 简介)

Spring MVC 初始化源码分析

Spring MVC 工作流程源码分析

Spring MVC 源码分析之 DispatcherServlet#getHandler 方法

** DispatcherServlet#getHandlerAdapter方法源码分析**

DispatcherServlet#getHandlerAdapter方法就是从 handlerAdapters 中查询匹配当前请求的 Handler,只要找到了就不在循环直接返回,我们我们重点关注adapter.supports(handler) 这行代码,这里实际调用的是接口的抽象类 AbstractHandlerMapping 中的 getHandler 方法,下面接着分析。

java 复制代码
//org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	this.handlerAdapters 为空判断 DispatcherServlet 初始化时注册的 handlerAdapters
	if (this.handlerAdapters != null) {
		//迭代遍历
		Iterator var2 = this.handlerAdapters.iterator();

		while(var2.hasNext()) {
			HandlerAdapter adapter = (HandlerAdapter)var2.next();
			//找到匹配当前 handler的 adapter
			if (adapter.supports(handler)) {
				//找到就返回
				return adapter;
			}
		}
	}
	//如果最后都没找到 抛出异常
	throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

AbstractHandlerMethodAdapter#supports 方法源码分析

AbstractHandlerMethodAdapter#supports 没有什么复杂的逻辑,只是判断了 handler 是否是 HandlerMethod 类型,至于 AbstractHandlerMethodAdapter#supportsInternal 方法它默认返回 fasle,也就是说只要 handler 是 HandlerMethod 类型,就算匹配成功。

java 复制代码
//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
public final boolean supports(Object handler) {
	//handler 是否是 HandlerMethod 类型 
	// this.supportsInternal 抽象方法 由子类实现  RequestMappingHandlerAdapter#supportsInternal 默认返回 true
	return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
}
//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supportsInternal
protected abstract boolean supportsInternal(HandlerMethod var1);

//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal
protected boolean supportsInternal(HandlerMethod handlerMethod) {
	return true;
}

HandlerExecutionChain#applyPreHandle 方法源码分析

HandlerExecutionChain#applyPreHandle 方法的主要左右就是调用拦截器的 preHandle 方法,如果有某个拦截器的 preHandle 方法返回 false,就会逆向调用返回 true 的拦截器的 triggerAfterCompletion 方法。

java 复制代码
//org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//获取所有拦截器数组
	HandlerInterceptor[] interceptors = this.getInterceptors();
	//为空判断
	if (!ObjectUtils.isEmpty(interceptors)) {
		//循环调用 拦截器的 preHandle 方法
		//this.interceptorIndex 记录当前拦截器的位置
		for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
			HandlerInterceptor interceptor = interceptors[i];
			//判断拦截器的 preHandle 方法返回值
			if (!interceptor.preHandle(request, response, this.handler)) {
				//拦截器 preHandle 方法返回 false 则反向调用返回 true 的那些拦截器的 afterCompletion 方法
				this.triggerAfterCompletion(request, response, (Exception)null);
				//返回 false
				return false;
			}
		}
	}

	return true;
}


//org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
	//获取所有拦截器
	HandlerInterceptor[] interceptors = this.getInterceptors();
	//为空判断
	if (!ObjectUtils.isEmpty(interceptors)) {
		//反向遍历 这里是的 interceptorIndex 上面记录了的 --i 就是反向遍历
		for(int i = this.interceptorIndex; i >= 0; --i) {
			HandlerInterceptor interceptor = interceptors[i];

			try {
				//调用拦截器的 afterCompletion 方法
				interceptor.afterCompletion(request, response, this.handler, ex);
			} catch (Throwable var8) {
				logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
			}
		}
	}

}

HandlerExecutionChain#applyPostHandle 方法源码分析

拦截器的 preHandle 方法调用完成后,就会调用 handle 方法处理具体请求(后面分析),handle 方法调用完成后就会调用拦截器的 applyPreHandle 方法, HandlerExecutionChain#applyPreHandle 方法的主要左右就是逆向调用拦截器的 postHandle 方法。

java 复制代码
//org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
	//获取所有拦截器
	HandlerInterceptor[] interceptors = this.getInterceptors();
	//为空判断
	if (!ObjectUtils.isEmpty(interceptors)) {
		for(int i = interceptors.length - 1; i >= 0; --i) {
			//逆向调用拦截器的 postHandle 方法
			HandlerInterceptor interceptor = interceptors[i];
			interceptor.postHandle(request, response, this.handler, mv);
		}
	}

}

本篇主要分析了 Spring MVC 工作流程中比较简单的几个关键点,HandlerAdapter 的适配过程、拦截器的前置后置处理等,这些在流程中比较简单的环节就放在一起分析了,希望可以帮助到有需要的朋友。

欢迎提出建议及对错误的地方指出纠正。

相关推荐
abcnull12 分钟前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡18 分钟前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手34 分钟前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan1 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054731 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路1 小时前
C++23概述
java·c++·c++23
专注API从业者2 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠2 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
keep one's resolveY3 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克33 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信