三个Servlet
一、HttpServletBean
参与创建工作,没有涉及请求的处理
二、FrameworkServlet
当第一个请求过来时,就初始化容器
如上图,当第一个请求过来时,FrameworkServlet就初始化容器,并将Spring的容器进行刷新,而DispatcherServlet的onRefresh刷新只是初始化九大组件。以后的请求就都不需要初始化容器。
初始化完容器以后,因为FrameworkServlet重写了Servlet的service,doGet,doPost等方法,所以会先走到Framework的doGet或者doPost等请求方法。
FrameworkServlet的设计很有趣,它将所有的请求get,post,delete等请求全部嫁接到processRequest(request,response)
processRequest.png
在processRequest(request,response)方法中又调用了doService(request,response)方法,该方法是在DispatcherServlet中具体实现
所以说FrameworkServlet主要有两个作用:
1.创建并初始化Spring容器
2.请求的入口
三、DispatcherServlet
第一个作用是初始化九大组件,就是在上面的FrameworkServlet执行完初始化容器后,就调用onRefresh,方法里面只调用了initStrategies(context)方法,initStrategies方法才是重点,如下图
每个组件在处理请求时都有可能会用到
第二个作用就是处理请求
请求的入口是doService ,我们看下请求过来的调用链
doService对request设置了一些属性
doService.png
接着调用doDispatch,doDispatch是DispatcherServlet的核心
我们看代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
*
* doDispatch中最重要的代码总共有四句(见下面的标签数字)
*
* Handler、HandlerMapping、HandlerAdapter三者的关系:
* Handler:就是我们的控制器Controller中加了@XXXMapping的方法
* HandlerMapping: 用来快速查找Handler
* HandlerAdapter:调用Handler来干活,而且不同Handler需要不同的Adapter
* 这就好比HandlerAdapter是工人,Handler是工具,HandlerMapping是根据加工的需求来选择用
* 什么设备
*/
/**
* 封装Request,如果不是上传请求则直接使用接收到的request
* 如果是上传请求,重新封装成MultipartHttpServletRequest
*/
HttpServletRequest processedRequest = request;
/**
* 处理请求的处理器链
* 包含有处理器Handler和对应的拦截器Interceptor
*/
HandlerExecutionChain mappedHandler = null;
/**
* 是否为上传请求的标记
*/
boolean multipartRequestParsed = false;
/**
* 从request中获取异步请求
*/
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
/**
* View 跟 ViewResolver
* View 是用来展示数据的
* 而ViewResolver是用来查找View的
* 做完请求工作后,需要返回结果,而返回结果就需要模板,
* View就是所需要的模板,ViewResolver就是来选择哪个模板
*
* **/
ModelAndView mv = null;
/**
* 异常声明
* doDispatch()中对异常又两种处理方法:
* 一、如果是处理请求中出现的异常,会捕获并在processDispatchResult中渲染到最后的视图中
* 二、如果是渲染中出现异常,则直接抛出
*/
Exception dispatchException = null;
try {
// 检查是不是上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
/** 第一句
* 使用HandlerMapping找到可以干活的Handler
*
* **/
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 找不到Handler返回404
noHandlerFound(processedRequest, response);
return;
}
/** 第二句
* 找到合适的HandlerAdapter去让他干活
* **/
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理GET、HEAD请求的last-modified
// Process last-modified header, if supported by the handler.
/**
* Last-Modified是HTTP头部的一种属性,表示当前请求的资源跟上一次请求的资源是否相同
* 如果相同,返回304并且没有新的实体(body)返回
* 否则返回新的实体内容
*
* 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,
* 同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。
* 客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过
* 如果服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。
* 当服务器端代码发生改变或者重启服务器时,则重新发出资源,
* 返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
*/
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;
}
}
/** 如果有拦截器,就饿执行我们的拦截器,preHandle前置处理**/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
/** 第三句
* 让HandlerAdapter开始干活,干完活后返回数据
* **/
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 如果需要异步处理,则直接返回
/**
* 因为异步处理会重新开启一个线程去执行结果的返回
* 不会占用目前这个线程,所以可以直接返回
*/
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 当view为空时(比如,handler返回类型为void),根据request设置默认view
applyDefaultViewName(processedRequest, mv);
/** 执行了拦截器的后置处理 postHandle**/
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
/** 第四句
* 将数据处理,通过View展示给用户
* 处理结果,包括处理异常,渲染页面,发出完成通知,触发拦截器的afterCompletion
* **/
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
// 判断是否为异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
// 执行异步的拦截器
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 删除上传请求的资源,不然会产生临时的资源
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
doDispatch方法主要有四个任务:1.用request找到Handler; 2.根据Handler找到HandlerAdapter; 3.用HandlerAdapter处理Handler 4.调用processDispatchResult方法处理结果(包括异常的处理和View视图的渲染)。
除此之外还另外做了许多事情,比如判断是否为上传文件请求,是否带有Last-Modified头部,执行拦截器,是否为异步请求...
processDispatchResult方法处理上面doDispatch返回的结果,包括处理异常、渲染页面、触发拦截器的后置处理,处理异常只是处理doDispatch()方法中的异常、渲染页面的异常就抛出。渲染页面的方法调用render
网友评论