DispatherServlet 源码解析
2022/4/3 17:21:56
本文主要是介绍DispatherServlet 源码解析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
DispatherServlet 初始化做了什么?
在 DispatherServlet 的 OnRefresh()方法打上断点,可以看到是 Servlet 生命周期 init() 方法一直调用到了 OnRefresh() 方法, OnRefresh() 又调用了 initStrategies() 方法
![image-20220403101707090](/images/baidian.png)
在 DispatherServlet 的 initStrategies() 方法中,有9个方法完成了DispatherServlet 的初始化过程
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
initMultipartResolver
Multipart:是文件上传的一种格式,这个方法是初始化文件上传时用到的解析器
initLocaleResolver
spring对于国际化的支持,只要是关于一些本地化解析器的初始化,解决语言问题
![image-20220403101345607](/images/baidian.png)
-
AcceptHeaderLocaleResolver:从请求头中获取本地信息
-
CookieLocaleResolver:从 Cookie 中获取本地信息
initHandlerMappings
建立一个请求路径与控制器方法的映射
- 所有的请求都会来到 DispatherServlet ,当时所有的请求都会由某个控制器方法来执行
- HandlerMapaping:路径映射器,其中有一个实现就是用来解析 RequestMapping:RequestMappingHandlerMapping
/** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. * 初始化 HandlerMappings,如果 BeanFactory中没有,则使用默认的 BeanNameUrlHandlerMapping */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; // detectAllHandlerMappings 探测所有的 HandlerMapping,SpringMVC中父子容器,当前容器没有,则会去父容器探测 if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. // 如果没有发现其他的映射,通过注册一个默认的 HandlerMapping 来确保我们至少有一个 HandlerMapping if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); } for (HandlerMapping mapping : this.handlerMappings) { if (mapping.usesPathPatterns()) { this.parseRequestPath = true; break; } } }
getDefaultStrategies 就是去类路径下读取 DispatcherServlet.properties 这个文件
![image-20220403121946612](/images/baidian.png)
在 DispatcherServlet.properties 中定义了三个 HandlerMappiing
将这三个 HandlerMapping 的实现类加入到 DispatcherServlet 的成员变量 handlerMappings 中
![image-20220403124413127](/images/baidian.png)
这里为了测试方便,直接将 RequestMappingHandlerMapping 注入到 IOC 容器中
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping(){ return new RequestMappingHandlerMapping(); }
从容器中获取 RequestMappingHandlerMapping 对象,获得路径与控制器方法的映射关系
// 作用 解析 @RequestMapping 以及派生注解,生成路径与控制器方法的映射关系,在初始化时就生成 RequestMappingHandlerMapping requestMappingHandlerMapping = ac.getBean(RequestMappingHandlerMapping.class); /* RequestMappingInfo:请求参数,请求路径,请求方式 封装在该对象中 HandlerMethod:哪个控制器的哪个方法 */ Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods(); handlerMethods.forEach((k, v) -> { logger.debug("K:{}==V:{}",k,v); });
结果:
也就是解析了我们自己写的 Controller1 这个控制器
![image-20220403125756899](/images/baidian.png)
/* 请求来了,获取控制器方法 HandlerExecutionChain:处理器执行链,封装了 handlerMethods 以及一些拦截器 */ HandlerExecutionChain chain = requestMappingHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/test1")); logger.debug("{}",chain);
执行结果:
找到一个执行链,Controller1中 test1方法,并且没有拦截器
getHandlerMethods:是去 RequestMappingHandlerMapping 对象的成员变量 mappingRegistry 中获取并进一步封装,这个 mappingRegistry 是什么时候初始化的呢?
可以看到 RequestMappingHandlerMapping 是继承了 RequestMappingHandlerMapping ,在 RequestMappingHandlerMapping 中有一个方法:afterPropertiesSet() ,afterPropertiesSet() 是在Spring Bean生命周期过程中自动调用的,mappingRegistry 初始化就是在这个方法中完成的
![image-20220403134104422](/upload/202204/03/202204031721568074.png)
执行链:
afterPropertiesSet -> initHandlerMethods() -> processCandidateBean(beanName) -> detectHandlerMethods(beanName) -> registerHandlerMethod(handler, invocableMethod, mapping)
initHandlerAdapters
- 适配不同形式的控制器方法,然后去调用他们,简单来说就是去调用控制器方法的,它也有多种实现
initHandlerExceptionResolvers
- 控制器方法有可能出现异常,解析异常
- 出现异常之后,该怎么解析
这篇关于DispatherServlet 源码解析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)