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;
    }
}
原文地址:https://www.cnblogs.com/chenxingyang/p/15550526.html