现在我们的项目基本上都是采用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()方法的重写
/**
* Delegate GET requests to processRequest/doService.
* Will also be invoked by HttpServlet's default implementation of {@code doHead},
* with a {@code NoBodyResponse} that just captures the content length.
* @see #doService
* @see #doHead
*/
@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);
}
}
/**
* Process this request, publishing an event regardless of the outcome.
* The actual event handling is performed by the abstract
* {@link #doService} template method.
*/
通过该方法的注释,可以了解到processRequest
此方法最终处理请求事件的处理器,是该类的抽象方法doService
,其实现方法写在了子类DispatcherServlet
中。
在DispatcherServlet
找到对doService
的实现方法,观察到其注释告诉我们,他将特定的属性和请求方法发送给doDispatch
方法进行实际的调度。
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
继续找到doDispatch
方法,先看其注释
/**
* Process the actual dispatching to the handler.
* The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
*
All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
注释说明,实际上是这个方法对请求做实际的分派,通过按顺序查找注册的HandlerMappings映射,获取查询到的第一个处理器。并且所有的 HTTP 方法都是由此方法做处理的
通过阅读doDispatch
方法,可以在其方法内找到一行注释以及一个方法:
这行注释告诉我们是getHandler
这个方法来确定当前请求的处理器
进入getHandler
方法内部
/**
* Return the HandlerExecutionChain for this request.
* Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code 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;
}
我们启动项目,请求一个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中,其中包含了路径、方法等信息,在接收到请求时,会从注册的映射处理器中查找对应的路径方法,最后分发到方法中进行处理。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)