zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    python依赖包整体迁移方法
    ubuntu关于ssh协议登录问题
    k8s部署02-----kubeadm部署k8s
    k8s部署01-----what is k8s?
    兼容到ie10的js文件导出、下载到本地
    webstorm减少内存占用
    foxmail占cpu 100%解决办法
    原生js返回顶部
    js字符串驼峰和下划线互相转换
    element-ui的rules中正则表达式
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15550526.html
Copyright © 2011-2022 走看看