在分析之前,先介绍一个类
1、HandlerExecutionChain
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private HandlerInterceptor[] interceptors;
private List interceptorList;
private int interceptorIndex;
该类中主要包括了一个用于处理request的handler,以及和request相关的一系列拦截器interceptors.
进入正题,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 {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
/*
分析1,其目的是:得到包含了用于处理request的HandlerMethod、Interceptors。
*/
mappedHandler = this.getHandler(processedRequest, false);
//如果没有,则说明没有处理器能够处理该request,因此返回404错误。
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
/*
分析2,其目的是:得到与Handler匹配的HandlerAdapter。
*/
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if(this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
/*
分析3:执行所有注册拦截器的preHandler方法
*/
if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
//前面的第一步就是找到用于处理request的handler,到这里才真正意思上的执行用于处理request的handler方法。具体后面进行分析
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
this.applyDefaultViewName(request, mv);
/*
分析4:执行所有注册拦截器的postHandler方法
*/
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var27) {
dispatchException = var27;
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception var28) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
} catch (Error var29) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
}
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
} else {
if(multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
}
doDispatch方法主要逻辑如下:
1)找到用于处理request的handler和interceptors,构造成一个HandlerExecutionChain.
2) 找到与用于处理request的handler相匹配的HandlerAdapter,目的是:后续将使用此HandlerAdapter来执行handler。
3)执行所有注册拦截器的preHandler方法
4)真正意思上的执行用于request的handler方法,得到ModelAndView
5)倒序执行所有注册拦截器的postHandler方法。
6)解析并返回ModelAndView
主要是理清思路,本篇博文将依次分析除第4点之外的几点。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
该函数的功能为:遍历DispatcherServlet中的private List handlerMappings; 看哪个HandlerMapping能够处理该request,则返回由
AbstractHandlerMapping.java
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);//第一步
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//第二步
return getHandlerExecutionChain(handler, request);
}
此方法的主要逻辑如下:
第一步:根据request中的url得到相应的handler,此handler为HandlerMethod的实例。
第二步:将第一步得到的HandlerMethod作为参数实例化一个HandlerExecutionChain对象。在实例化过程中,还需要得到与request相关的Interceptors。
下面将逐一的分析这两步所涉及到具体实现。
先看第一步:根据request中的url得到相应的handler,此handler为HandlerMethod的实例
getHandlerInternal方法的代码如下:
AbstractHandlerMethodMapping.java
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//得到与request相关的handlerMethod,如何得到的,就是在Map中来寻找
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
getHandlerInternal函数的功能:就是在Map中寻找HandlerMethod方法。Map中保存的是
,Map中的内容如何来的呢:是在容器初始化时会建立所有url和controller的对应关系,保存到Map
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)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
其中,private final List
中保存的是我们项目配置文件配置的拦截器。
new ArrayList
DispatcherServlet.java
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
该getHandlerAdapter函数的功能为:判断private List
中哪个Adapter能支持这个handler。或者说,这个handler应该与哪个Adapter进行搭档才能正常工作。
从Debug的情况来看,如果我们采用的是@RequestMapping注解形式,则获取到的是HandlerAdapter 是RequestMappingHandlerAdapter类的一个实例。
以下就是RequestMappingHandlerAdapter的support方法的实现,即只要此时的handler为HandlerMethod的实例,就是支持的。
AbstractHandlerMethodAdapter.java
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
RequestMappingHandlerAdapter
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;//interceptorIndex标示着拦截器数组中下标小于等于interceptorIndex的拦截器已经被成功执行。
}
}
return true;
}
该函数的功能为:调用所有注册拦截器的preHandle方法,如果preHandle方法的返回结果为true,则会继续执行下面的程序。如果preHandler方法返回false,则调用triggerAfterCompletion方法。该方法的代码如下:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
从代码中可以看到:triggerAfterCompletion方法它会调用所有已经成功执行的拦截器的afterCompletion方法,而且是反序调用的过程。
以上可以得到的结论为:
1)只有所有注册的拦截器都执行成功,即都返回true,则doDispathcer中的代码才会继续执行。
2)如果第i个拦截器返回false,则会触发triggerAfterCompletion方法来反序执行刚刚所有已经成功执行的拦截器的afterCompletion方法。并返回false从而使得doDispatcher中的代码就不会往下执行了。
看到这里,我们也就明白了拦截器的作用。
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
该函数的功能:反序执行所有注册的拦截器的postHandler方法,比较简单哈。
就这样我们稍微理清了下doDispatch这个方法的基本思路,有很多细节,博文中并没有关注,如果你有兴趣,可以仔细研究。
========================漂亮的分割线========================
博文的以上部分可以看作是SpringMVC用于处理Http请求的运行主线的源码分析。而没有分析初始化主线。在看了这篇博文之后(http://downpour.iteye.com/blog/1341459),感觉对SpringMVC的初始化主线又多了一份了解。
总结如下:
1、基于框架所编写的应用程序的构成三要素。
a)入口程序DispatcherServlet,在web.xml文件中定义。
b)核心配置文件,[servlet-name]-servlet.xml文件。里面定义了相关组件。
c)控制逻辑,Controller。
2、框架的具体实现。
有两条主线。
a)初始化主线 -- 负责对SpringMVC的运行要素进行初始化。
b)用于处理http请求的运行主线 -- 负责对SpringMVC中的组件进行逻辑调度完成对Http请求的处理。
这两条主线的划分是根据servlet中的init方法和service方法来的,这两个方法的运行时间和触发条件截然不同。其中,init方法在整个系统启动时运行,且只运行一次。因此,在init方法中我们往往会对整个应用程序进行初始化操作。而service方法在整个系统运行的过程中一直处于监听模式,侦听并处理所有的web请求。
SpringMVC的整个运行体系,是由DispatcherServlet、组件和容器这三者共同构成的。 既然是三个元素之间的关系表述,我们必须以两两关系的形式进行归纳:
DispatcherServlet - 容器 —— DispatcherServlet负责对容器进行初始化,初始化的依据是核心配置文件
容器 - 组件 —— 容器对组件进行全局管理
DispatcherServlet - 组件 —— DispatcherServlet对组件进行逻辑调用
2.1)初始化主线。
首先要明确3个观点。
a)初始化主线的驱动方法:init().
b) 初始化主线的执行次序(根据DispatcherServlet的继承结构而来):HttpServletBean–>FrameworkServlet–>DispatherServlet.
c) 初始化主线的操作对象:Spring容器(WebApplicatonContext)以及组件.
(配图)
2.2)用于处理http请求的运行主线。
(配图)