码迷,mamicode.com
首页 > 编程语言 > 详细

SpringMVC源代码学习(二)FrameworkServlet内处理请求的流程

时间:2016-05-13 00:12:47      阅读:372      评论:0      收藏:0      [点我收藏+]

标签:

以下内容基于书:《看透SpringMVC-源代码分析与实践》
基本照搬。。。用于自己查阅备忘。

先看一眼DispatcherServlet继承树
技术分享

我们知道servlet处理方法都是通过HttpServlet的service方法开始,FrameworkServlet重写了父类HttpServlet的service方法。代码如下:

FrameworkServlet service

protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    /*
    因为HttpServlet中是没有定义doPatch方法的,所以规定
    if(是doPatch类型)
        就交由本类(FrameworkServlet)内的doPatch方法运行。
    else
        调用父类(HttpServlet)的service方法。
    */
    if (HttpMethod.PATCH.matches(request.getMethod())) {
        processRequest(request, response);
    }
    else {
        super.service(request, response);
    }
}

HttpServlet的service是根据类型调用不同的do方法。如doGet,doPost。这些方法在FrameworkServlet内被重写了,所以最终调用的还是FrameworkServlet内的相应方法。
代码如下(以doGet为例):

FrameworkServlet(doxxx)

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    processRequest(request, response);
}

我们总结一下这个流程,以doGet为例
get request->FrameworkServlet(service)->判断是不是patch请求:不是->HttpServlet(service)->判断是什么类型:get->HttpServlet(doGet)->doGet被子类重写->FrameworkServlet(doGet)->FrameworkServlet(processRequest)

FrameworkServlet内的其他doxxx请求也是类似的,最终都是processRequest(request, response);来处理,也就是说在HttpServlet的service方法内doxx先按类型分开,然后在FrameworkServlet的doxx合并到一个方法处理。绕了一个大弯

  1. 之所以重新合并,原因还没看到,应该是不同类型的请求在spring内部还需要进行统计处理。
  2. 之所以不直接利用service进行处理,原因书上有讲,主要是出于灵活性的考虑吧,写过代码的同学应该都能理解。

下面我们就看下processRequest方法,代码如下:

FrameworkServlet(processRequest)

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        //先获取LocaleContext与RequestAttributes备份起来
        //用于在finally中进行恢复
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = buildLocaleContext(request);

        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        //将当前的localeContext,requestAttributes覆盖进去
        initContextHolders(request, localeContext, requestAttributes);

        try {
            //实际处理请求的地方
            doService(request, response);
        }
        catch(...){//catch代码没理解上的意义,被我删掉了
        }
        finally {
            //恢复相关信息,因为在service可能还有Filter等操作
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }
            //log...
            //发布Event,类型是ServletRequestHandledEvent,这个下面有解释
            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }

从细节看,
LocaleContextHolder是一个abstract class,没有实现的class,内部的方法都是静态的,用法就是不实例化直接调用,通过它可以获得LocaleContext,也就是语言等本地化信息,如”zh-cn”。 一般获取Locale的方法是request.getLocale(),LocaleContextHolder内的方法因为是静态的,可以随时随地调用,更方便一些。
RequestContextHolder也是一样的道理。通过RequestContextHolder可以get到request与session。

关于发布与监听事件
publishEvents设置为true时,请求处理结束后就会发出这个消息,publishEvents在web.xml文件配置SpringMVC的servlet时配置,默认为true。
那怎么做到监听这个事件呢,很简单,demo如下:

//做两件事 1、@Component注解。  2、实现ApplicationListener
@Component
    public class ServletRequestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent>{
    final static Logger logger = LoggerFactory.getLogger("RequestProcessLog");
    @override
    public void onApplicationEvent(ServletRequestHandledEvent event){
        logger.info(event.getDescription());
    }
}

doService(request, response);
这行语句是实际处理请求的核心语句,它是个抽象方法,交给子类,也就是DispatcherServlet实现。
所以我们下篇博客就观察DispatcherServlet的代码。

SpringMVC源代码学习(二)FrameworkServlet内处理请求的流程

标签:

原文地址:http://blog.csdn.net/xia4820723/article/details/51338015

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!