五、请求处理—Rest映射是怎样实现的?
这节我们来分析一下,每次收到一个请求,springboot是怎样找到对应的方法处理的?
因为springboot底层还是用的Spring MVC,所以,所有的请求过来,会先来到DispatcherServlet ,DispatcherServlet是处理所有请求的开始。
从源码可以看到,DispatcherServlet继承了FrameworkServlet,FrameworkServlet继承了HttpServletBean,HttpServletBean继承了HttpServlet,所以 DispatcherServlet本质上也是一个Servlet ,是Servlet就必然要重写doGet(),doPost()等方法
查找发现在HttpServletBean中没有doGet(),doPost()等,考虑在它的子类中重写了,再检查它的子类FrameworkServlet,在这个类中找到了这些方法
而且我们发现,不管是doGet()还是doPost()等,里边调用的都是 processRequest(request, response);
所以接下来,我们来看processRequest()这个方法里边做了什么?
我们来继续跟进本类的doService(request, response);
进入doService(request, response)方法发现,这是一个抽象方法,没有实现,所以就来到了它的子类DispatcherServlet,可以看到,最终是在DispatcherServlet中对doService()方法进行实现的。
来到doService()方法,上边的一些获取值代码可以先不看,来到下边有一个 doDispatch(request, response); 方法,从方法名可以猜出他就是用来做转发的
看到这里我们可以得出,每个请求进来,都会调用这个doDispatch()方法,也就是说,要分析SpringMVC的功能,我们都从 DispatcherServlet类中的doDispatch()方法开始 。
找到的分析的入口,接下来我们来debug一下,详细看看doDispatch()方法做了什么?
首先,我们来发送一个@GetMapping(“/user”)请求,下面将debug的过程记录在代码注释
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//先把原生的request请求进行了包装
HttpServletRequest processedRequest = request;
//执行链后边再说
HandlerExecutionChain mappedHandler = null;
//是否文件上传请求,默认false
boolean multipartRequestParsed = false;
//如果有异步,使用异步管理器,暂时不管
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//检查是否文件上传请求
processedRequest = this.checkMultipart(request);
//如果是进行转化
multipartRequestParsed = processedRequest != request;
//这里决定哪个Handler可以处理当前请求,我们要找的就是这里,下边进入该方法
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//HandlerMapping:处理器映射,保存了所有@RequestMapping 和handler的映射规则。
//在应用一启动,spring mvc 自动扫描所有的controller保存的
//循环查找看谁能处理这个请求
//debug部分截图在下边
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
HandlerMapping 保存了我们所有的映射,进行循环查找对比,最后找到由哪个controller的哪个类型的方法处理。
到这里,HandlerMapping 映射的原理就分析清楚了,后边还有一大段代码我们还没有看,这节只是分析请求映射原理,后边的下回再说。
总结一下:
● SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 “/” 能访问到 index.html
● SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
● 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息
○ 如果有就找到这个请求对应的handler
○ 如果没有就尝试下一个 HandlerMapping
● 另外,我们也可以自己给容器中放HandlerMapping,自定义 HandlerMapping,有兴趣可以试试。