7、SpringMVC拦截器源码分析
2019-06-02 本文已影响0人
那谁319
拦截器执行节点
- Web请求被DispatcherServlet截获后,会调用DispatcherServlet的doDispatch方法。
DispatcherServlet.doDispatch执行逻辑
DispatcherServlet.doDispatch.png- 简单梳理doDispatch的执行流程
- 获取Handler
- 获取Adapter
- 执行applyPreHandle,(调用HandlerExecutionChain的applyPreHandle方法)
- 执行handle方法
- 执行applyPostHandle,(调用HandlerExecutionChain的applyPostHandle方法)
- 异常处理,(调用HandlerExecutionChain的triggerAfterCompletion方法)
- 处理返回结果
HandlerExecutionChain的applyPreHandle方法执行逻辑
HandlerExecutionChain.applyPreHandle.png- 循环执行所有的拦截器的preHandle方法,返回结果为false会执行triggerAfterCompletion方法。
HandlerExecutionChain的applyPostHandle方法执行逻辑
HandlerExecutionChain.applyPostHandle.png- 循环执行所有的拦截器的postHandle方法。
HandlerExecutionChain的triggerAfterCompletion方法执行逻辑
HandlerExecutionChain.triggerAfterCompletion.png- 循环执行所有的拦截器的afterCompletion方法。
问题汇总
- 从以上的源码者可以看出拦截器的执行流程。但是这些一下问题似乎没有回答:
- 1、拦截器何时创建的?
- 2、这些拦截器又是什么时候被HandlerExecutionChain对象所持有的呢?
- 3、一个请求过来该执行那些拦截器是什么时候确定的?
一份配置demo
interceptors.pngMvcNamespaceHandler.init()执行逻辑
namespaceHandler-init.png- 从初始化的解析器列表来看,对照配置demo,重点关注interceptors元素匹配的解析器InterceptorsBeanDefinitionParser。
InterceptorsBeanDefinitionParser.parse(参数)执行逻辑
nterceptorsBeanDefinitionParser.parse.png- 简单总结下parse方法主要是注册自定义拦截器bean。
获取Handler(HandlerExecutionChain)
-
我们知道doDispatch的执行流程中会首先获取Handler,我们看下获取Handler的执行逻辑。
DispatcherServlet.getHandler.png - 循环比遍历已经初始化的handlerMappings,调用handlerMapping的getHandler方法。
- 根据request参数获取对应的HandlerMethod对象;
- 调用getHandlerExecutionChain方法。
- 判断参数handler是否匹配HandlerExecutionChain,如果是把参数handler赋值给HandlerExecutionChain对象chain,如果不是new HandlerExecutionChain(handler);
- 获取请求path,循环遍历adaptedInterceptors集合,添加匹配路径的拦截器到HandlerExecutionChain对象。
- 可以看到拦截器的匹配是根据指定includePatterns和excludePatterns做条件进行匹配和过滤。
AbstractHandlerMapping的adaptedInterceptors 属性
- 从上面的代码中我们看到HandlerExecutionChain对象持有的当前请求匹配的拦截器是从AbstractHandlerMapping的adaptedInterceptors 属性获取的,那么AbstractHandlerMapping的adaptedInterceptors 属性是什么时候被赋值的呢?
- adaptedInterceptors既然是AbstractHandlerMapping的属性,我们清楚的是其子类RequestMappingHandlerMapping对象,所以adaptedInterceptors属性的赋值,应该和RequestMappingHandlerMapping的加载有关。
- 从XmlWebApplicationContext.refresh()执行逻辑中我们知道RequestMappingHandlerMapping类会被懒加载。而spring在执行refresh()逻辑时会添加实现BeanPostProcessor接口的ApplicationContextAwareProcessor,在后续bean加载完成前后会调用postProcessBeforeInitialization和postProcessAfterInitialization方法。其中postProcessBeforeInitialization逻辑中会通过判断当前实例化的bean是否ApplicationContextAware,如果匹配则执行 ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
RequestMappingHandlerMapping类继承关系
RequestMappingHandlerMapping.png- 由RequestMappingHandlerMapping的类继承图可以看到,其实现了ApplicationContextAware接口,所以当RequestMappingHandlerMapping被懒加载时会执行((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
- 主要调用initApplicationContext(ApplicationContext context)方法。
- 调用子类AbstractHandlerMapping重写的initApplicationContext()方法。
- 给adaptedInterceptors赋值;
- 并初始化所有的拦截器。