SpringMVC拦截器
一、使用
1. 继承 HandlerInterceptor
public interface HandlerInterceptor { // Handler 被调用前执行, 返回 false 则不再向下执行 default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } // Handler 执行后 // 若 Handler 执行过程中间解析过程发生异常, 不会执行, 说白了 preHandle 和 postHandle 都在 try块中 default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } // Handler 执行完毕后, 且异常处理完毕/视图解析器渲染完毕后执行 default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
2. 注入 HandlerInterceptor
实现接口重写方法注入实例,交给Spring管理
public interface WebMvcConfigurer { default void addInterceptors(InterceptorRegistry registry) { } }
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // Ant 风格拦截 url registry.addInterceptor(new DemoHandlerInterceptor()).addPathPatterns("/**"); } }
二、 原理
1. 调用
public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { try { try { // 得到处理器链, 处理器和拦截器封装在一起的 HandlerExecutionChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // preHandle 调用 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); applyDefaultViewName(processedRequest, mv); // post 调用 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException("Handler dispatch failed", err); } // 异常处理器处理异常 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // afterCompletion 调用 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { // afterCompletion 调用 triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } }
2. 查找
public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // 得到处理器链, 处理器和拦截器封装在一起的 HandlerExecutionChain mappedHandler = getHandler(processedRequest); // 处理器映射器查找处理器链 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; } } // 这里仅考虑 RequestMappingHandlerMapping public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware { public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); } protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { // 注意我们自定义的拦截器被封装为了 MappedInterceptor if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { // 添加拦截器 chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; } }
3. 注入
仅考虑 RequestMappingHandlerMapping
这里详细的需要去看 RequestMappigHandlerMapping的讲解
主要是 DelegatingWebMvcConfiguration 收集/注入了所有 WebMvcConfigurer 配置,然后 RequestMappingHandlerMapping 创建时注入拦截器
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WebProperties.class) public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware { @Bean @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping( @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { // Must be @Primary for MvcUriComponentsBuilder to work return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider); } } } // 【父类】 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); // 【!!!】注入了所有 WebMvcConfigurer, 显然包含我们所注入的 @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } // 重写的父类的 protected void addInterceptors(InterceptorRegistry registry) { this.configurers.addInterceptors(registry); } } // 【成员变量】 class WebMvcConfigurerComposite implements WebMvcConfigurer { // 链表, 封装对多个 WebMvcConfigurer 的访问 private final List<WebMvcConfigurer> delegates = new ArrayList<>(); // 需要传入一个注册器 InterceptorRegistry 进来 @Override public void addInterceptors(InterceptorRegistry registry) { for (WebMvcConfigurer delegate : this.delegates) { delegate.addInterceptors(registry); } } } // RequestMappingHandlerMapping的创建, EnableWebMvcConfiguration 调用的父类的方法 public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware { public RequestMappingHandlerMapping requestMappingHandlerMapping(...) { // 实际是调用子类的, 若子类没有实现直接 new RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); // 在这里添加了所有拦截器 // 也就是我们需要自定义一个 HandlerMapping 的话, 也是需要自己处理的 mapping.setInterceptors(getInterceptors(...)); protected final Object[] getInterceptors(...) { if (this.interceptors == null) { InterceptorRegistry registry = new InterceptorRegistry(); // 子类调用, 当前类实现为空, 实现类是上面说过的 DelegatingWebMvcConfiguration, 它收集了所有 WebMvcConfigurer addInterceptors(registry); // ... 添加了两个内部的, 封装的是 HandlerInterceptor, 它们没有设置 addPathPatterns 设置拦截路径 this.interceptors = registry.getInterceptors(); } return this.interceptors.toArray(); } }
4. 类型区别
这里区别类型应该是用来提高效率的,没有配置的直接所有路径都调用,配置了路径的才会解析进行选择性调用
InterceptorRegistry 封装拦截器为 InterceptorRegistration public class InterceptorRegistry { // 封装 public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) { InterceptorRegistration registration = new InterceptorRegistration(interceptor); this.registrations.add(registration); return registration; } protected List<Object> getInterceptors() { return this.registrations.stream() .sorted(INTERCEPTOR_ORDER_COMPARATOR) // 调用了 getInterceptor 获取拦截器, 里面将拦截器进一步封装 .map(InterceptorRegistration::getInterceptor) .collect(Collectors.toList()); } } public class InterceptorRegistration { protected Object getInterceptor() { // 当没有设置拦截路径时或排除的路径时直接返回, 实际一般直接是 HandlerInterceptor 实现类 if (this.includePatterns == null && this.excludePatterns == null) { return this.interceptor; } // 否则封装为 MappedInterceptor MappedInterceptor mappedInterceptor = new MappedInterceptor( StringUtils.toStringArray(this.includePatterns), StringUtils.toStringArray(this.excludePatterns), this.interceptor); if (this.pathMatcher != null) { mappedInterceptor.setPathMatcher(this.pathMatcher); } return mappedInterceptor; } }