SpringMvc拦截器运行原理。

首先,先简单的说一下怎么配置SpringMvc的拦截器。java

分两步,第一步先定义一个类,实现HandlerInterceptor接口。web

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class TestInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("preHandle invoke");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle invoke");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("afterCompletion invoke");
        
    }

}

第二布,配置springMvc.xmlspring

<!-- 拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/*"/>
            <bean class="com.mmc.interceptor.TestInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

完工。下面分析原理tomcat

打开这个DispatcherServlet类,这个类是SpringMvc中最核心的一个类。答案就在doDispatch方法里面:mvc

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;

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                try {
                    // Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }

                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }

里面我标红了四处,第一处对应执行自定义拦截器的preHandler方法,第二处对应执行你的Controller类中的RequestMapping映射的处理方法,第三处是自定义拦截器的postHandle方法,第四处是自定义拦截器的afterCompletion方法。app


 

这些可能不少人都知道,可是咱们确定还有疑问,为何他能调用到个人拦截器里写的方法呢?框架

 接着往下分析。async


 

因而咱们点开我第一处标红那里的mappedHandler.applyPreHandle方法。代码以下:ide

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (getInterceptors() != null) {
            for (int i = 0; i < getInterceptors().length; i++) {
                HandlerInterceptor interceptor = getInterceptors()[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

看得出来,他是在遍历getInterceptors(),因此在点开这个方法。post

public HandlerInterceptor[] getInterceptors() {
        if (this.interceptors == null && this.interceptorList != null) {
            this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
        }
        return this.interceptors;
    }
View Code

这里面有两个变量,interceptorList和interceptors。这时我确定会猜测,确定是某个时候系统框架把这两个变量赋值了,而后在我执行方法的时候都会去看看这两个变量是否是有值的。有就执行拦截器。

那么这两个变量是何时赋值的呢?找到定义这两个变量的地方,他们是在HandlerExecutionChain类里面,我把断点打在这个变量定义那里。debug运行,代码停在了HandlerExecutionChain里面

 

 

 看debug模式中的方法执行顺序,点到doDispatch方法里面,在执行applyPreHandle即调用拦截器的方法以前,有一个getHandler方法,这个方法里面有getHandlerExecutionChain方法。这个方法里面有以下代码:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain =
            (handler instanceof HandlerExecutionChain) ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);

        chain.addInterceptors(getAdaptedInterceptors());

        String lookupPath = urlPathHelper.getLookupPathForRequest(request);
        for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
            if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }

        return chain;
    }

注意看,里面有一句chain.addInterceptor(mappedInterceptor.getInterceptor());这个从名字就知道是添加拦截器。而这个拦截器是从mappedInterceptor得到的属性,mappedInterceptor是遍历mappedInterceptors获得的。而这个对象在我运行这个的时候就已经存在了。因此我思考是否是启动项目的时候就已经初始化了,并且是根据个人xml配置文件来初始化的。因而我在mappedInterceptors对象处打断点,启动tomcat。果真代码执行到了。在AbstractHandlerMapping类中找到了这个方法,

@Override
    protected void initApplicationContext() throws BeansException {
        extendInterceptors(this.interceptors);
        detectMappedInterceptors(this.mappedInterceptors);
        initInterceptors();
 

 在这个detectMappedInterceptors(this.mappedInterceptors);里面即是将mappedInterceptors对象赋值了。下面我就不贴代码了。就是去找MappedInterceptor类,这个类是根据xml文件中<mvc:interceptor>的内容来构建的。构建方法在InterceptorsBeanDefinitionParser类里面。

顺着来一遍就是这样的:

 启动项目,InterceptorsBeanDefinitionParser类会根据配置文件构建MappedInterceptor对象集合,当我发送请求的时候,系统去看这个集合里有没有值,若是有值,就遍历执行这个对象,取得这个对象中的HandlerInterceptor属性,也就是我自定义的拦截器的对象。而后去执行我这个拦截器中的三个方法。到此拦截器的运行原理就分析完了。

 

有分析不对的地方请不吝指出

相关文章
相关标签/搜索