栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot 是如何请求到对应Controller的@RequestMapping方法的?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot 是如何请求到对应Controller的@RequestMapping方法的?

现在我们的项目基本上都是采用springboot来编写的。springboot相比于传统的spring项目,引入了自动化配置,减少了繁琐的配置,大大的提高了我们的开发效率。
在SpringBoot项目中,我们通常在相应的controller中定义我们的方法。

@RestController
public class HelloController {
    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}

那么当我们通过postman调用这个方法时,springboot是如何将请求分发到我们相应的方法的呢?下面就来简单的分析下

DispatcherServlet 类

DispatcherServlet 译为分发器,其作用如其名,是 Spring 接收请求的中心调度类,此类就是专门负责将web请求分派给已注册的合适的处理程序处理Web请求
DispatcherServlet继承于FrameworkServlet
FrameworkServlet继承于HttpServletBean
HttpServletBean继承于HttpServlet

public class DispatcherServlet extends FrameworkServlet {
// 以省略属性和方法
}

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
// 以省略属性和方法
}

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
// 以省略属性和方法
}

我们由postmsn发送的请求一般包括一下几种:

  • GET
  • POST
  • PUT
  • DELETE
  • OPTIONS
    每一种请求都会调用一种对应的方法来处理,比如GET请求,就会由doGet()方法进行处理。而doGet方法被定义在了HttpServlet抽象类中

通关对继承树的观察,我们在HttpServlet的子类FrameworkServlet中发现了对doGet()方法的重写

	
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

重写后的doGet方法实际上调用了另外一个方法processRequest
进入到这个方法中

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 省略部分代码

		try {
			doService(request, response);
		}
		catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}
			logResult(request, response, failureCause, asyncManager);
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
 

通过该方法的注释,可以了解到processRequest此方法最终处理请求事件的处理器,是该类的抽象方法doService,其实现方法写在了子类DispatcherServlet中。

在DispatcherServlet找到对doService的实现方法,观察到其注释告诉我们,他将特定的属性和请求方法发送给doDispatch方法进行实际的调度。

	

继续找到doDispatch方法,先看其注释

   

注释说明,实际上是这个方法对请求做实际的分派,通过按顺序查找注册的HandlerMappings映射,获取查询到的第一个处理器。并且所有的 HTTP 方法都是由此方法做处理的

通过阅读doDispatch 方法,可以在其方法内找到一行注释以及一个方法:

这行注释告诉我们是getHandler这个方法来确定当前请求的处理器

进入getHandler方法内部

	
	@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;
	}

我们启动项目,请求一个hello测试接口
我们通过计算器查看handlerMapping,如下

可以看到有很多HandlerMapping,第一个(索引为0)的为RequestMappingHandlerMapping 就是和我们的请求息息相关的handlerMapping.
在进入RequestMappingHandlerMapping内部,如下图

直接找到mappingRegistry查看 如下图

就可以看到,里面维护了我们定义的所有的RequestMapping方法
而我此时请求的就是下面这个方法

@RestController
public class HelloController {
    @GetMapping("hello")
    public String hello(){
        return "hello";
    }
}

当我们getHandler并传入当前request对象的时候,就可以看到如下图

此时已经成功找到了处理该请求的方法,然后就是后续调用该方法进行请求的处理了

mappingRegistry中的数据是如何来的呢?

其实Spring Boot在启动后,会将所有扫描到的@RequestMapping注解注册到映射处理器handlerMappings中,其中包含了路径、方法等信息,在接收到请求时,会从注册的映射处理器中查找对应的路径方法,最后分发到方法中进行处理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/825585.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号