具体参考:Spring MVC 原理探秘 - 一个请求的旅行过程
Spring MVC流程图
组件:
- DispatcherServlet:Spring MVC 的核心组件,是请求的入口,负责协调各个组件工作。
- HandlerMapping:内部维护了一些 <访问路径, 处理器> 映射,负责为请求找到合适的处理器。
- HandlerAdapter:处理器的适配器。Spring 中的处理器的实现多变,比如用户处理器可以实现 Controller 接口,也可以用 @RequestMapping 注解将方法作为一个处理器等,这就导致 Spring 不止到怎么调用用户的处理器逻辑。所以这里需要一个处理器适配器,由处理器适配器去调用处理器的逻辑。
- ViewResolver:视图解析器的用途不难理解,用于将视图名称解析为视图对象 View。
- View:视图对象用于将模板渲染成 html 或其他类型的文件。比如 InternalResourceView 可将 jsp 渲染成 html。
Servlet
接口及其实现类结构
GenericServlet:实现了 Servlet 和 ServletConfig 两个接口,为这两个接口中的部分方法提供了简单的实现。比如该类实现了 Servlet 接口中的 void init(ServletConfig) 方法,并在方法体内调用了内部提供了一个无参的 init 方法,子类可覆盖该无参 init 方法。除此之外,GenericServlet 还实现了 ServletConfig 接口中的 getInitParameter 方法,用户可直接调用该方法获取到配置信息。
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable {
// 省略部分代码
private transient ServletConfig config;
public GenericServlet() { }
/** 有参 init 方法 */
public void init(ServletConfig config) throws ServletException {
this.config = config;
// 调用内部定义的无参 init 方法
this.init();
}
/** 无参 init 方法,子类可覆盖该方法 */
public void init() throws ServletException { }
/** 未给 service 方法提供具体的实现 */
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
public void destroy() { }
/** 通过 getInitParameter 可直接从 ServletConfig 实现类中获取配置信息 */
public String getInitParameter(String name) {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameter(name);
}
public ServletConfig getServletConfig() {
return config;
}
// 省略部分代码
}
HttpServlet:这个类是和 HTTP 协议相关。该类的关注点在于怎么处理 HTTP 请求,比如其定义了 doGet 方法处理 GET 类型的请求,定义了 doPost 方法处理 POST 类型的请求等。我们若需要基于 Servlet 写 Web 应用,应继承该类,并覆盖指定的方法。doGet 和 doPost 等方法并不是处理的入口方法,所以这些方法需要由其他方法调用才行。
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
// 调用重载方法,该重载方法接受 HttpServletRequest 和 HttpServletResponse 类型的参数
service(request, response);
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
// 处理 GET 请求
if (method.equals(METHOD_GET)) {
//获取Request的最后修改时间,若时间unknown,默认返回-1
long lastModified = getLastModified(req);
if (lastModified == -1) {
// 调用 doGet 方法
doGet(req, resp);
} else {
//上次服务器告诉它的文件最后修改时间
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
//判断是否已经修改更新
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
//返回304状态,浏览器用缓存诗句
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
// 处理 HEAD 请求
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
// 处理 POST 请求
} else if (method.equals(METHOD_POST)) {
// 调用 doPost 方法
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
DispatcherServlet 族谱
Aware
用于向 Spring “索要”一些框架中的信息。比如当某个 bean 实现了 ApplicationContextAware 接口时,Spring 在运行时会将当前的 ApplicationContext 实例通过接口方法 setApplicationContext 传给该 bean。
EnvironmentCapable
EnvironmentCapable 仅包含一个方法定义 getEnvironment,通过该方法可以获取到环境变量对象。通常可以EnvironmentCapable和 EnvironmentAware 接口配合使用。
如下这个例子:
public class EnvironmentHolder implements EnvironmentCapable, EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public Environment getEnvironment() {
return environment;
}
}
HttpServletBean
HttpServletBean 是 HttpServlet 抽象类的简单拓展。HttpServletBean 覆写了父类中的无参 init 方法,并在该方法中将 ServletConfig 里的配置信息设置到子类对象中,比如 DispatcherServlet。
FrameworkServlet
FrameworkServlet 是 Spring Web 框架中的一个基础类,该类会在初始化时创建一个容器。同时该类覆写了 doGet、doPost 等方法,并将所有类型的请求委托给 doService 方法去处理。doService 是一个抽象方法,需要子类实现。
DispatcherServlet
DispatcherServlet 主要的职责相信大家都比较清楚了,即协调各个组件工作。除此之外,DispatcherServlet 还有一个重要的事情要做,即初始化各种组件,比如 HandlerMapping、HandlerAdapter 等。
DispatcherServlet 源码简析
分析 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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否是请求multipart如文件上传,如果是,则将通过multipartResolver解析
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取可处理当前请求的处理器 Handler,对应流程图中的步骤②
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取可执行处理器逻辑的适配器 HandlerAdapter,对应步骤③
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理 last-modified 消息头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行拦截器 preHandle 方法(预处理)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用处理器逻辑,对应步骤④
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如果 controller 未返回 view 名称,这里生成默认的 view 名称
applyDefaultViewName(processedRequest, mv);
// 执行拦截器 preHandle 方法(后处理)
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 解析并渲染视图
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 {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
// 渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {...
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
/*
* 若 mv 中的 view 是 String 类型,即处理器返回的是模板名称,
* 这里将其解析为具体的 View 对象
*/
if (mv.isReference()) {
// 解析视图,对应步骤⑤
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
if (logger.isDebugEnabled()) {...}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 渲染视图,并将结果返回给用户。对应步骤⑥和⑦
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {...}
throw ex;
}
}
以上介绍了Servlet和DispatcherServlet方面的知识,从源码的角度分析了 DispatcherServlet 处理请求的过程。