美文网首页js css html一些收藏
Spring Interceptor深度解析

Spring Interceptor深度解析

作者: 晴天哥_王志 | 来源:发表于2022-07-10 09:27 被阅读0次

    背景

    • 介绍Interceptor的案例。
    • Interceptor的解析,HandlerMapping和Interceptor的绑定。
    • HandlerExecutionChain的拦截器链的构建。
    • HandlerExecutionChain的执行流程。

    Interceptor案例

    @Component
    public class TimeInterceptor extends HandlerInterceptorAdapter {
    
        private final NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("startTimeThreadLocal");
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            System.out.println("time interceptor postHandle");
    
            // 获取处理当前请求的 handler 信息
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            System.out.println("handler 类:" + handlerMethod.getBeanType().getName());
            System.out.println("handler 方法:" + handlerMethod.getMethod().getName());
    
            MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
            for (MethodParameter methodParameter : methodParameters) {
                // 只能获取参数的名称,不能获取到参数的值
                String parameterName = methodParameter.getParameterName();
                System.out.println("parameterName: " + parameterName);
            }
    
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("time interceptor postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
            System.out.println("time interceptor afterCompletion");
        }
    }
    
    • 通过继承HandlerInterceptorAdapter实现拦截器类并实现preHandle、postHandle、afterCompletion等方法。
    <bean id="xxxx" class="com.lg.mvc.interceptor.TimeInterceptor"/>  
    <mvc:interceptors>  
        <mvc:interceptor>  
            <mvc:mapping path="xxx"/>  
            <mvc:exclude-mapping path="xxxx"/>
            <ref bean="logMvcInterceptor"/>
        </mvc:interceptor>  
    </mvc:interceptors>  
    
    • 通过在xml文件中定义mvc:interceptors定义拦截器和对应匹配的路径。
    • 通过interceptor标签的InterceptorsBeanDefinitionParser解析拦截器定义。

    Interceptor解析流程

    http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
    
    
    public class MvcNamespaceHandler extends NamespaceHandlerSupport {
    
        @Override
        public void init() {
            registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
            registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
            registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
            registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
            registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
            registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
            registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
            registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
            registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
            registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
            registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
            registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
            registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
            registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
        }
    }
    
    • 通过InterceptorsBeanDefinitionParser来解析interceptors的配置项。
    class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {
    
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
            parserContext.pushContainingComponent(compDefinition);
    
            RuntimeBeanReference pathMatcherRef = null;
            if (element.hasAttribute("path-matcher")) {
                pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
            }
    
            List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor");
            for (Element interceptor : interceptors) {
                RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
                mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));
                mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    
                ManagedList<String> includePatterns = null;
                ManagedList<String> excludePatterns = null;
                Object interceptorBean;
                if ("interceptor".equals(interceptor.getLocalName())) {
                    includePatterns = getIncludePatterns(interceptor, "mapping");
                    excludePatterns = getIncludePatterns(interceptor, "exclude-mapping");
                    Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0);
                    interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null);
                }
                else {
                    interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null);
                }
                mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);
                mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);
                mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean);
    
                if (pathMatcherRef != null) {
                    mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
                }
    
                String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
                parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));
            }
    
            parserContext.popAndRegisterContainingComponent();
            return null;
        }
    }
    
    • 解析Interceptor的xml配置生成MappedInterceptor的BeanDefinition。
    • 每个mvc:interceptor标签解析生成一个MappedInterceptor对象。
    public final class MappedInterceptor implements HandlerInterceptor {
    
        private final String[] includePatterns;
        private final String[] excludePatterns;
        private final HandlerInterceptor interceptor;
        private PathMatcher pathMatcher;
    
        public MappedInterceptor(String[] includePatterns, HandlerInterceptor interceptor) {
            this(includePatterns, null, interceptor);
        }
    
        public MappedInterceptor(String[] includePatterns, String[] excludePatterns, HandlerInterceptor interceptor) {
            this.includePatterns = includePatterns;
            this.excludePatterns = excludePatterns;
            this.interceptor = interceptor;
        }
    
        public MappedInterceptor(String[] includePatterns, WebRequestInterceptor interceptor) {
            this(includePatterns, null, interceptor);
        }
    
        public MappedInterceptor(String[] includePatterns, String[] excludePatterns, WebRequestInterceptor interceptor) {
            this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor));
        }
    
        public void setPathMatcher(PathMatcher pathMatcher) {
            this.pathMatcher = pathMatcher;
        }
    
        public PathMatcher getPathMatcher() {
            return this.pathMatcher;
        }
    
        public String[] getPathPatterns() {
            return this.includePatterns;
        }
    
        public HandlerInterceptor getInterceptor() {
            return this.interceptor;
        }
    
        public boolean matches(String lookupPath, PathMatcher pathMatcher) {
            PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher);
            if (!ObjectUtils.isEmpty(this.excludePatterns)) {
                for (String pattern : this.excludePatterns) {
                    if (pathMatcherToUse.match(pattern, lookupPath)) {
                        return false;
                    }
                }
            }
            if (ObjectUtils.isEmpty(this.includePatterns)) {
                return true;
            }
            for (String pattern : this.includePatterns) {
                if (pathMatcherToUse.match(pattern, lookupPath)) {
                    return true;
                }
            }
            return false;
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            return this.interceptor.preHandle(request, response, handler);
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
    
            this.interceptor.postHandle(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) throws Exception {
    
            this.interceptor.afterCompletion(request, response, handler, ex);
        }
    }
    
    • MappedInterceptor包含includePatterns和excludePatterns和interceptor核心变量。
    • includePatterns代表包含的匹配路径,excludePatterns代表排除的匹配路径,interceptor代表拦截器对象。
    • matches方法负责查找Request匹配的Interceptor对象。

    RequestMappingHandlerMapping

    • HandlerMapping的构建过程中会建立和Interceptors的关联关系。
    • RequestMappingHandlerMapping是HandlerMapping的一种实现形式。
    • RequestMappingHandlerMapping的初始化过程中通过父类AbstractHandlerMapping负责建立和Interceptors的关联关系。
    public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
    
        private Object defaultHandler;
        private UrlPathHelper urlPathHelper = new UrlPathHelper();
        private PathMatcher pathMatcher = new AntPathMatcher();
        private final List<Object> interceptors = new ArrayList<Object>();
        private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
        private final UrlBasedCorsConfigurationSource globalCorsConfigSource = new UrlBasedCorsConfigurationSource();
        private CorsProcessor corsProcessor = new DefaultCorsProcessor();
    
        @Override
        protected void initApplicationContext() throws BeansException {
            extendInterceptors(this.interceptors);
            detectMappedInterceptors(this.adaptedInterceptors);
            initInterceptors();
        }
    
        protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
            mappedInterceptors.addAll(
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(
                            getApplicationContext(), MappedInterceptor.class, true, false).values());
        }
    }
    
    • AbstractHandlerMapping的interceptors和adaptedInterceptors保存Interceptor。
    • detectMappedInterceptors保存的是解析生成的MappedInterceptor类。

    HandlerExecutionChain

    public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
    
        private int order = Integer.MAX_VALUE;  // default: same as non-Ordered
        private Object defaultHandler;
        private UrlPathHelper urlPathHelper = new UrlPathHelper();
        private PathMatcher pathMatcher = new AntPathMatcher();
        private final List<Object> interceptors = new ArrayList<Object>();
        private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
        private final UrlBasedCorsConfigurationSource globalCorsConfigSource = new UrlBasedCorsConfigurationSource();
        private CorsProcessor corsProcessor = new DefaultCorsProcessor();
    
        @Override
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            Object handler = getHandlerInternal(request);
            HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
            return executionChain;
        }
    
    
        protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
            HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                    (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
            // 根据请求的path获取interceptor
            String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
            for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
                if (interceptor instanceof MappedInterceptor) {
                    MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                    // 匹配查找对应的interceptor
                    if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                        chain.addInterceptor(mappedInterceptor.getInterceptor());
                    }
                }
                else {
                    chain.addInterceptor(interceptor);
                }
            }
            return chain;
        }
    }
    
    • AbstractHandlerMapping的getHandler方法返回HandlerExecutionChain的拦截器链。
    • AbstractHandlerMapping的getHandlerExecutionChain遍历adaptedInterceptors添加到HandlerExecutionChain中。

    拦截器执行流程

    public class DispatcherServlet extends FrameworkServlet {
    
        protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;
            HandlerExecutionChain mappedHandler = null;
            boolean multipartRequestParsed = false;
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;
    
                try {
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
                    // mappedHandler代表的是HandlerExecutionChain职责链
                    mappedHandler = getHandler(processedRequest);
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    // 执行mappedHandler的applyPreHandle方法
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    // 执行controller的执行逻辑
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    applyDefaultViewName(processedRequest, mv);
                    // 执行mappedHandler的applyPostHandle方法
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                }
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
            }
            finally {
            }
        }
    
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            for (HandlerMapping hm : this.handlerMappings) {
                // RequestMappingHandlerMapping
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
            return null;
        }
    }
    
    • mappedHandler.applyPreHandle负责执行拦截器Interceptor的preHandle方法。
    • ha.handle负责执行controller的逻辑方法。
    • mappedHandler.applyPostHandle负责执行拦截器Interceptor的postHandle方法。
    public class HandlerExecutionChain {
        private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
        private final Object handler;
        private HandlerInterceptor[] interceptors;
        private List<HandlerInterceptor> interceptorList;
        private int interceptorIndex = -1;
    
        public HandlerInterceptor[] getInterceptors() {
            if (this.interceptors == null && this.interceptorList != null) {
                this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
            }
            return this.interceptors;
        }
    
        boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = 0; i < interceptors.length; i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        triggerAfterCompletion(request, response, null);
                        return false;
                    }
                    this.interceptorIndex = i;
                }
            }
            return true;
        }
    
        void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = interceptors.length - 1; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(request, response, this.handler, mv);
                }
            }
        }
    
        void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
                throws Exception {
    
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = this.interceptorIndex; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    try {
                        interceptor.afterCompletion(request, response, this.handler, ex);
                    }
                    catch (Throwable ex2) {
                    }
                }
            }
        }
    }
    
    • applyPreHandle负责遍历拦截器的preHandle方法。
    • applyPostHandle负责遍历拦截器的postHandle方法。

    Filter和Interceptor的调用链

          // 以下是自定义拦截器TimeInterceptor的调用链
          at com.nextyu.demo.web.interceptor.TimeInterceptor.preHandle(TimeInterceptor.java:31)
          at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:133)
          at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:962)
          at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
          at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
          at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
          at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
          // HttpServlet的实例是DispatcherServlet
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
          // 以下是Tomcat的处理逻辑
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          // 以下是自定义Filter对象TimeFilter的调用链
          at com.nextyu.demo.web.filter.TimeFilter.doFilter(TimeFilter.java:25)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
          at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
          at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
          at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
          at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
          at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
          at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
          at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
          at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
          at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
          at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
          - locked <0x14f6> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
          at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
          at java.lang.Thread.run(Thread.java:748)
    

    参考

    相关文章

      网友评论

        本文标题:Spring Interceptor深度解析

        本文链接:https://www.haomeiwen.com/subject/robibrtx.html