SpringMVC工作流程及拦截器实现原理

一、拦截器简介

拦截器是spring中的一个重要概念。他被注册到spring,拦截指定规则的请求,基于回调机制执行。一般来说,拦截器只会拦截action请求,这一点与过滤器不同。

下面贴一张spring web请求的执行流程图:

 

二、拦截器原理

1、拦截器定义

因为拦截器主要是对controller起作用,所以一般在webapp/WEB-INF下的类似spring-web-servlet.xml这样的配置文件中定义拦截器:

<mvc:interceptors>

   <mvc:interceptor>

       <mvc:mapping path="/main/*"/>

       <bean class="com.chengc.demos.web.demo1.interceptor.FirstInterceptor"/>

   </mvc:interceptor>

   <mvc:interceptor>

       <mvc:mapping path="/main/*"/> 

       <bean class="com.chengc.demos.web.demo1.interceptor.SecondInterceptor"></bean>

   </mvc:interceptor>

   <mvc:interceptor>

       <mvc:mapping path="/main/*"/> 

       <bean class="com.chengc.demos.web.demo1.interceptor.ThirdInterceptor"></bean>

   </mvc:interceptor>

</mvc:interceptors>

2、拦截器创建

Web容器在初始化DispatcherServlet(父类为FrameworkServlet)时,会创建其独有的XmlWebApplicationContext。在初始化该context,FrameworkServlet.configureAndRefreshWebApplicationContext中有一句wac.refresh()时,会在finishBeanFactoryInitialization(beanFactory)方法中调用AbstractHandlerMapping.initApplicationContext方法:

private final List<Object> interceptors = new ArrayList<Object>();

private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();

protected void initApplicationContext() throws BeansException {

    // 默认空实现

    extendInterceptors(this.interceptors);

    // 找到定义的interceptor

    detectMappedInterceptors(this.mappedInterceptors);

    // Interceptors进行初始化

    initInterceptors();

}

  • AbstractHandlerMapping.detectMappedInterceptors

protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {

    mappedInterceptors.addAll(

            BeanFactoryUtils.beansOfTypeIncludingAncestors(

                    getApplicationContext(), MappedInterceptor.classtruefalse).values());

}

该方法就会去初始化所有interceptor,调用他们的<clinit><init>

3、拦截器调用

先经过过滤器(机会多所有请求进行过滤),然后才会到拦截器。

  • DispatcherServlet会对请求进行doDispatch分发:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

    HttpServletRequest processedRequest = request;

    HandlerExecutionChain mappedHandler = null;

    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {

        // 传给ViewResolver进行视图解析的对象

        ModelAndView mv = null;

        Exception dispatchException = null;

        try {

            processedRequest = checkMultipart(request);

            multipartRequestParsed = processedRequest != request;

            // 为当前请求准备好HandlerExecutionChain

            mappedHandler = getHandler(processedRequest, false);

            if (mappedHandler == null || mappedHandler.getHandler() == null) {

                noHandlerFound(processedRequest, response);

                return;

            }

            // 为当前请求准备好HandlerAdapter

            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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

                    return;

                }

            }

            // 调用handler执行链上的interceptorpreHandle方法

            if (!mappedHandler.applyPreHandle(processedRequest, response)) {

                return;

            }

            try {

                // 真正调用handler(Controller)处理请求

                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            }

            finally {

                if (asyncManager.isConcurrentHandlingStarted()) {

                    return;

                }

            }

            applyDefaultViewName(request, mv);

            // 逆序调用handler执行链上的interceptorpostHandle方法

            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);

        }

    }

}

3.1、getHandler

getHandler主要是为当前request创建一个包含了若干路径匹配的interceptor和一个handler(即Controller)的HandlerExecutionChain(执行链)。

  • DispatcherServlet.getHandler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

    // 这里的handlerMappings就包含了最常用的RequestMappingHandlerMapping

    for (HandlerMapping hm : this.handlerMappings) {

        HandlerExecutionChain handler = hm.getHandler(request);

        if (handler != null) {

            return handler;

        }

    }

    return null;

}

这里看看hm.getHandler,在AbstractHandlerMapping.getHandler方法:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

    // 这一步就是根据request的路径找到Controller

    Object handler = getHandlerInternal(request);

    if (handler == null) {

        handler = getDefaultHandler();

    }

    if (handler == null) {

        return null;

    }

    // Bean name or resolved handler?

    // 正常的Controller应该是HandlerMethod

    if (handler instanceof String) {

        String handlerName = (String) handler;

        handler = getApplicationContext().getBean(handlerName);

    }

    // 获取该Controller的执行链

    return getHandlerExecutionChain(handler, request);

}

  • AbstractHandlerMethodMapping.getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

    // 请求的相对路径,比如/main/index

    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

    // 这一步会真正创建含有目标handlerMethodHandlerMethod对象

    return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

}

  • AbstractHandlerMapping.getHandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {

    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?

            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    chain.addInterceptors(getAdaptedInterceptors());

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

    // 将我们前面提到的注册的拦截器读取遍历

    for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {

        if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {

        // 如果拦截器的mapping和请求的路径匹配上了,就添加到该Handler的执行链中

            chain.addInterceptor(mappedInterceptor.getInterceptor());

        }

    }

    // 最后得到加上了拦截器的HandlerExecutionChain

    return chain;

}

这里,HandlerChain已经加入了interceptor:

 

3.2、getHandlerAdapter

为当前请求创建合适的HandlerAdapter,准备开始执行handler:

一般Controller返回的就是RequestMappingHandlerAdapter

这就是典型的适配器模式,将某个Controller类适配为RequestMappingHandlerAdapter,后续会反射执行其方法。

3.3、preHandle

这个阶段会调用handler执行链上的interceptor的preHandle方法。

HandlerExecutionChain.applyPreHandle方法,这里就会调用所有符合该请求的路径映射的interceptor的preHandle方法:

  • HandlerExecutionChain.applyPreHandle

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {

    if (getInterceptors() != null) {

        // 遍历执行链上的Interceptor

        for (int i = 0; i < getInterceptors().length; i++) {

            HandlerInterceptor interceptor = getInterceptors()[i];

            // 这里就在调用每个interceptorpreHandle方法了

            if (!interceptor.preHandle(request, response, this.handler)) {

            // interceptor返回true代表给下一个handler

            // 返回false代表调用链结束,直接调用handlers.afterCompletion方法.

                triggerAfterCompletion(request, response, null);

                return false;

            }

            this.interceptorIndex = i;

        }

    }

    return true;

}

3.4、HandlerAdapter.handle

这个阶段利用handler适配器真正调用handler执行代码逻辑。

我们直接看最关键的类InvocableHandlerMethod

private Object invoke(Object... args) throws Exception {

    // handler的目标方法设为可访问

    ReflectionUtils.makeAccessible(getBridgedMethod());

    try {

        // 对目标handler实例调用目标方法

        return getBridgedMethod().invoke(getBean(), args);

    }

} 

可以看到,SpringMVC内是通过反射的方式访问目标handler的方法。

以上的getBridgedMethodgetBean两个方法都来自于该类的父类HandlerMethod,存储了目标handler的Bean和Method。

这里返回的信息可以是ModelAndView, 代表视图路径的字符串,纯信息字符串等。还需要进一步加工处理。经过加工后,都转为ModelAndView

3.5、postHandle

逆序调用handler执行链上的interceptor的postHandle方法:HandlerExecutionChain.applyPostHandle

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {

    if (getInterceptors() == null) {

        return;

    }

    // 这里就能看到,为什么说是逆序调用postHandle

    for (int i = getInterceptors().length - 1; i >= 0; i--) {

        HandlerInterceptor interceptor = getInterceptors()[i];

        interceptor.postHandle(request, response, this.handler, mv);

    }

}

3.6、processDispatchResult-视图解析

该步骤主要是处理ModelAndView,ViewResolver解析后得到View。然后将该View处理后,放入response,最终返回给客户端。

  • DispatcherServlet.render

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

    // 请求来源的区域

    Locale locale = this.localeResolver.resolveLocale(request);

    // response也用相同区域

    response.setLocale(locale);

    View view;

    if (mv.isReference()) {

    // mv指向视图的索引,需要ViewSolver解析

        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

        if (view == null) {

            throw new ServletException("...")

        }

    }

    else {

    // ModelAndView本身就包含真实的视图对象

        view = mv.getView();

        if (view == null) {

            throw new ServletException("...");

        }

    }

    // Delegate to the View object for rendering.

    // 解析视图,放入

    try {

        view.render(mv.getModelInternal(), request, response);

    }

    catch (Exception ex) {

        if (logger.isDebugEnabled()) {

            logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +

                    getServletName() + "'", ex);

        }

        throw ex;

    }

}

3.7、triggerAfterCompletion

该步骤作为收尾步骤,主要是逆序执行interceptors的afterCompletion方法:HandlerExecutionChain.triggerAfterCompletion

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)

            throws Exception {

    if (getInterceptors() == null) {

        return;

    }

    // 逆序遍历执行interceptorafterCompletion方法

    for (int i = this.interceptorIndex; i >= 0; i--) {

        HandlerInterceptor interceptor = getInterceptors()[i];

        try {

            interceptor.afterCompletion(request, response, this.handler, ex);

        }

        catch (Throwable ex2) {

            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);

        }

    }

}

4、注意事项

拦截器依据器定义顺序执行的,如果想规定其执行顺序则可以使用注解@Order

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值