DispatcherServlet 如何准确地确定调用哪个控制器?
How does DispatcherServlet exactly figures out which controller to call?
假设我有一个用@Controller 注释的class 以及像这样的实例方法的相应映射。
@Controller
@ResponseBody
public class UserController {
@GetMapping("/example")
public User fetchUserExample() {
// ...
}
}
此外,假设有 1000 个控制器,如上所示,具有不同的 URL 映射。
我调用了 URL 中的任何一个,找到了相应的控制器,调用了相应的方法并返回了响应。
但令我感到困惑的是,dispatcherServlet 究竟是如何知道在哪里可以找到所请求的方法的 URL?它会逐一扫描每个控制器 classes 以寻找匹配项吗?它是否会针对每个请求执行此操作?如果是这样,这似乎并不是一个有效的方法。
我知道我们也可以对 class 进行注释,但这仍然不能回答问题,因为它仍然需要扫描 classes 以进行匹配。
我希望它能保持某种关于控制器及其各自映射的跟踪。
我为此在谷歌上搜索了很多,但几乎无论我走到哪里,都只是浏览了表面,@GetMapping, @RequestMapping
等注释告诉它调用的方法。但我们知道这一点。 dispatcherServlet 首先是如何定位 class 的,还是遵循我上面写的方法?
有些网站提到了诸如 HandlerMapping, SimpleControllerHandlerAdapter, RequestMappingHandlerAdapter
之类的内容,但由于我是 Spring 的新手,所以我无法理解这些内容是如何出现在此处的。
如有任何意见,我们将不胜感激。
由于映射注释是静态的并且在运行时永远不会更改,因此它不需要扫描每个控制器 class 来在处理请求时找到匹配的方法。只需在应用程序启动时扫描一次并将扫描结果存储到一种地图中。所以找到请求调用哪个方法只是从这个映射中查找一些数据的问题,这应该是非常有效的。
如果您对实际代码感兴趣,请查看 RequestMappingHandlerMapping#lookupHandlerMethod()
以了解查找为请求调用哪个方法的逻辑。扫描结果存储到内部 MappingRegistry
,lookupHandlerMethod()
将从中获取数据以找到匹配的方法。
您也可以尝试获取一个 RequestMappingHandlerMapping
bean,通过以下方式获取 MappingRegistry
的映射:
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethodMapping = mapping.getHandlerMethods();
handlerMethodMapping.forEach((k,v)->{
System.out.println(k);
System.out.println(v);
System.out.println("-----");
});
这将打印出哪个 URL 请求映射到哪个处理程序方法。
假设我有一个用@Controller 注释的class 以及像这样的实例方法的相应映射。
@Controller
@ResponseBody
public class UserController {
@GetMapping("/example")
public User fetchUserExample() {
// ...
}
}
此外,假设有 1000 个控制器,如上所示,具有不同的 URL 映射。 我调用了 URL 中的任何一个,找到了相应的控制器,调用了相应的方法并返回了响应。
但令我感到困惑的是,dispatcherServlet 究竟是如何知道在哪里可以找到所请求的方法的 URL?它会逐一扫描每个控制器 classes 以寻找匹配项吗?它是否会针对每个请求执行此操作?如果是这样,这似乎并不是一个有效的方法。
我知道我们也可以对 class 进行注释,但这仍然不能回答问题,因为它仍然需要扫描 classes 以进行匹配。
我希望它能保持某种关于控制器及其各自映射的跟踪。
我为此在谷歌上搜索了很多,但几乎无论我走到哪里,都只是浏览了表面,@GetMapping, @RequestMapping
等注释告诉它调用的方法。但我们知道这一点。 dispatcherServlet 首先是如何定位 class 的,还是遵循我上面写的方法?
有些网站提到了诸如 HandlerMapping, SimpleControllerHandlerAdapter, RequestMappingHandlerAdapter
之类的内容,但由于我是 Spring 的新手,所以我无法理解这些内容是如何出现在此处的。
如有任何意见,我们将不胜感激。
由于映射注释是静态的并且在运行时永远不会更改,因此它不需要扫描每个控制器 class 来在处理请求时找到匹配的方法。只需在应用程序启动时扫描一次并将扫描结果存储到一种地图中。所以找到请求调用哪个方法只是从这个映射中查找一些数据的问题,这应该是非常有效的。
如果您对实际代码感兴趣,请查看 RequestMappingHandlerMapping#lookupHandlerMethod()
以了解查找为请求调用哪个方法的逻辑。扫描结果存储到内部 MappingRegistry
,lookupHandlerMethod()
将从中获取数据以找到匹配的方法。
您也可以尝试获取一个 RequestMappingHandlerMapping
bean,通过以下方式获取 MappingRegistry
的映射:
RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethodMapping = mapping.getHandlerMethods();
handlerMethodMapping.forEach((k,v)->{
System.out.println(k);
System.out.println(v);
System.out.println("-----");
});
这将打印出哪个 URL 请求映射到哪个处理程序方法。