springmvc详解(3)请求分发流程之拦截器 Handler
前言
当Servlet接收到请求后会最终调用doDispatch方法后会去找到对应的HandlerMapping,同时也会找到配置的拦截器,最终组成需要的HandlerExecutionChain执行链(这里省略部分代码保留主要功能):
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1.确定使用的handler
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 确定handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 拦截器前置调用
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 设置默认视图名
applyDefaultViewName(processedRequest, mv);
// 拦截器后置调用
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 分发结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
拦截器
在开发中拦截器的使用是比较频繁的,例如用户拦截器,权限拦截器等。sringmvc的拦截器提供了pre,post,after三种时期的方法(调用处理器方法前,调用后,返回数据后),非常方便的进行资源设置,释放等功能。
public interface HandlerInterceptor {
// 前
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
// 中
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
// 后
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
拦截器注册
现在看看拦截器是怎么注册的?spring提供两种方式。
1. 配置类注册EnableWebMvcConfiguration#setConfigurers
通常在开发中我们会使用自己编写实现WebMvcConfigurer接口的方式添加拦截器,并把注册类注册到IOC容器中,EnableWebMvcConfiguration#setConfigurers就会使用@Autowired进行制动注入。
java @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } }
最后把注册的拦截器注册到HandlerMapping当中去,(以RequestMappingHandlerMapping为例)代码如下,getInterceptors方法最终会调用所有WebMvcConfigurer实例添加拦截器的方法,从而将我们自定义的拦截器注册到HanderMapping当中去
```java
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
……
```
2. 以MappedInterceptor类实例或者子类直接注册到IOC容器中
由于HandlerMapping继承WebApplicationObjectSupport,再创建bean的时候会调用其initApplicationContext方法。而该方法会注册容器中的MappedInterceptor类的bean。
这样我们就可以使用这些拦截器了。
总结
最后以一个流程图直观总结一下其过程:
image.png