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屬性,也就是我自定義的攔截器的對象。而後去執行我這個攔截器中的三個方法。到此攔截器的運行原理就分析完了。

 

有分析不對的地方請不吝指出

相關文章
相關標籤/搜索