HandlerMapping的配置和设计原理
在初始化完成时,在上下文环境中已定义的所有的HandlerMapping都已经被加载了,这些加载的handlerMapping被放在一个List中并被排序,存储着HTTP请求对应的映射数据。这个List中的每一个元素都对应着一个具体的handlerMapping的配置,一般每一个handlerMapping可以持有一系列从URL请求道Controller的映射,而Spring MVC提供了一系列的HandlerMapping实现。
以SimpleUrlHandlerMapping这个handlerMapping为例来分析HandlerMapping的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来持有一系列的映射关系。通过这些在HandlerMapping中定义的映射关系,即这些URL请求和控制器的对应关系,使Spring MVC应用可以根据HTTP请求确定一个对应的Controller。具体来说,这些映射关系是确定接口类HandlerMapping来封装的,在HandlerMapping接口中定义了一个getHandler方法,通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain中,封装了具体的Controller对象,如下代码:
public interface HandlerMapping {
/**
* Name of the {@link HttpServletRequest} attribute that contains the path
* within the handler mapping, in case of a pattern match, or the full
* relevant URI (typically within the DispatcherServlet's mapping) else.
* <p>Note: This attribute is not required to be supported by all
* HandlerMapping implementations. URL-based HandlerMappings will
* typically support it, but handlers should not necessarily expect
* this request attribute to be present in all scenarios.
*/
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
/**
* Name of the {@link HttpServletRequest} attribute that contains the URI
* templates map, mapping variable names to values.
* <p>Note: This attribute is not required to be supported by all
* HandlerMapping implementations. URL-based HandlerMappings will
* typically support it, but handlers should not necessarily expect
* this request attribute to be present in all scenarios.
*/
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
/**
* Return a handler and any interceptors for this request. The choice may be made
* on request URL, session state, or any factor the implementing class chooses.
* <p>The returned HandlerExecutionChain contains a handler Object, rather than
* even a tag interface, so that handlers are not constrained in any way.
* For example, a HandlerAdapter could be written to allow another framework's
* handler objects to be used.
* <p>Returns {@code null} if no match was found. This is not an error.
* The DispatcherServlet will query all registered HandlerMapping beans to find
* a match, and only decide there is an error if none can find a handler.
* @param request current HTTP request
* @return a HandlerExecutionChain instance containing handler object and
* any interceptors, or {@code null} if no mapping found
* @throws Exception if there is an internal error
*/
/*
* 调用getHandler实际上返回的是一个HandlerExecutionChain,这是典型的Command的模式的使用,
* 这个HandlerExecutionChain不但持有handler本身,还包括了处理这个HTTP请求相关的拦截器
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
这个HandlerExecutionChain,它持有一个Interceptor链和一个handler对象,这个handler对象实际上就是HTTP请求对应的Controller,在持有这个handler对象的同时,还在HandlerExecutionChain中设置了一个拦截器链,通过这个拦截器链和handler都进行配置,这些配置都是在HandlerExecutionChain的初始化函数中完成的。为了维护这个拦截器链和handler,HandlerExecutionChain还提供了一系列与拦截器链维护相关的一些操作,如可以为拦截器链增加拦截器的addInterceptor方法等。HandlerExecutionChain的实现如下:
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
*/
public HandlerExecutionChain(Object handler) {
this(handler, null);
}
/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
* @param interceptors the array of interceptors to apply
* (in the given order) before the handler itself executes
*/
public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<HandlerInterceptor>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
else {
this.handler = handler;
this.interceptors = interceptors;
}
}
/**
* Return the handler object to execute.
* @return the handler object
*/
public Object getHandler() {
return this.handler;
}
public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList();
this.interceptorList.add(interceptor);
}
public void addInterceptors(HandlerInterceptor[] interceptors) {
if (interceptors != null) {
initInterceptorList();
this.interceptorList.addAll(Arrays.asList(interceptors));
}
}
private void initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<HandlerInterceptor>();
}
if (this.interceptors != null) {
this.interceptorList.addAll(Arrays.asList(this.interceptors));
this.interceptors = null;
}
}
/**
* Return the array of interceptors to apply (in the given order).
* @return the array of HandlerInterceptors instances (may be {@code null})
*/
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
}
return this.interceptors;
}
}
HandlerExecutionChain中定义的Handler和Interceptor需要在定义HandlerMapping时配置好,例如对具体的SimpleURLHandlerMapping,要做的就是根据URL映射的方式,注册Handler和Interceptor,从而维护一个反映这种映射关系的handlerMap。当需要匹配HTTP请求时,需要查询这个handlerMap中的信息来得到对应的HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对Bean进行依赖注入时发生,它实际上是通过一个Bean的postProcessor来完成的。
了解了这些调用关系的发生后,我们将进一步分析在SimpleUrlHandlerMapping中的注册过程是如何完成的,如下代码:
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
// 这里对Bean的配置进行解析,然后调用基类的registerHandler完成注册
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
}
}
这个SimpleUrlHandlerMapping注册过程的完成,很大一部分需要它的基类来配合,这个基类就是AbstractUrlHandlerMapping。AbstractUrlHandlerMapping中的处理如下代码。在这个处理过程中,如果使用Bean的名称作为映射,那么直接从容器中获取这个HTTP映射对应的Bean,然后还要对不同的URL配置进行解析处理,比如在HTTP请求中配置成”/“和通配符”/*“的URL,以及正常的URL请求,完成这个解析处理过程以后,会把URL和handler作为键值对放到一个handlerMap中去。
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
// 如果直接用bean名称进行映射,那就直接从容器中获取handler
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
if (getApplicationContext().isSingleton(handlerName)) {
resolvedHandler = getApplicationContext().getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else { // 处理URL是“/”的映射,把这个“/”映射的controller设置到rootHandler中
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
// 处理URL是“/*”的映射,把这个“/”映射的Controller设置到defaultHandler中
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
// 处理正常的URL映射,设置handlerMap的key和value,分别对应于URL和映射的controller
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
这里的handlerMap是一个HashMap,其中保存了URL请求和Controller的映射关系,这个handlerMap是在AbstractUrlHandlerMapping中定义的,如下所示:
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
这个配置好URL请求和handler映射数据的handlerMap,为Spring MVC响应HTTP请求准备好了基本的映射数据,根据这个handlerMap以及设置于其中的映射数据,可以方便地由URL请求得到它所对应的handler。有了这些准备工作,Spring MVC姐可以静静等待HTTP请求的到来了。
使用HandlerMapping完成请求的映射处理
通过SimpleUrlHandlerMapping的实现来分析HandlerMapping的接口方法getHandler,该方法会根据初始化时得到的映射关系来生成DispatcherServlet需要的HandlerExecutionChain,也就是说,这个getHandler方法是实际使用HandlerMapping完成请求的映射处理的地方。在前面的HandlerExecutionChain的执行过程中,首先在AbstractHandlerMapping中启动了getHandler的调用,如下代码:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
// 使用默认的Handler,也就是“/”对应的handler
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
// 这里通过名称取出对应的Handler Bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 这里把Handler封装到HandlerExecutionChain中并加上拦截器
return getHandlerExecutionChain(handler, request);
}
/**
* Build a {@link HandlerExecutionChain} for the given handler, including
* applicable interceptors.
* <p>The default implementation builds a standard {@link HandlerExecutionChain}
* with the given handler, the handler mapping's common interceptors, and any
* {@link MappedInterceptor}s matching to the current request URL. Subclasses
* may override this in order to extend/rearrange the list of interceptors.
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
* pre-built {@link HandlerExecutionChain}. This method should handle those
* two cases explicitly, either building a new {@link HandlerExecutionChain}
* or extending the existing chain.
* <p>For simply adding an interceptor in a custom subclass, consider calling
* {@code super.getHandlerExecutionChain(handler, request)} and invoking
* {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
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;
}
取得handler的具体过程在getHandlerInternal方法中实现,这个方法接受HTTP请求作为参数,它的实现在AbstractHandlerMapping的子类AbstractUrlHandlerMapping中,这个实现过程包括从HTTP请求中得到URL,并根据URL到urlMapping中获得handler,过程如下:
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 从request中得到请求的URL路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
/* 将得到的URL路径与Handler进行匹配,得到对应的Handlerm,如果没有对应的Handler,返回null
* 这样默认的Handler会被使用
*/
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
// 这里需要注意的是对默认handler的处理
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
/**
* Look up a handler instance for the given URL path.
* <p>Supports direct matches, e.g. a registered "/test" matches "/test",
* and various Ant-style pattern matches, e.g. a registered "/t*" matches
* both "/test" and "/team". For details, see the AntPathMatcher class.
* <p>Looks for the most exact pattern, where most exact is defined as
* the longest path pattern.
* @param urlPath URL the bean is mapped to
* @param request current HTTP request (to expose the path within the mapping to)
* @return the associated handler instance, or {@code null} if not found
* @see #exposePathWithinMapping
* @see org.springframework.util.AntPathMatcher
*/
// lookupHandler根据URL路径启动在handlerMap中对handler的检索,并最终返回handler对象
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// Pattern match?
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
}
String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
经过这一系列对HTTP请求进行解析和匹配handler的过程,得到了与请求对应的handler处理器。再返回的handler中,已经完成了在HandlerExecutionChain中的封装工作,为handler对HTTP请求的响应最好了准备。然而,在MVC中,还有一个重要的问题:请求是怎样实现分发,从而到达对应的handler的呢?有了前面的分析,如果再对前端HTTP请求分发的过程有所了解,那么基本上可以看到HTTP请求在MVC框架中处理过程的全貌了。
Spring MVC对HTTP请求的分发处理
我们需要看一下DispatcherServlet,毫无疑问,它是Spring MVC框架中非常重要的一个类,不但建立了自己持有的IoC容器,还肩负着请求分发处理的重任。在MVC框架初始化完成以后。,对HTTP请求的处理是在doService()方法中完成的。DispatcherServlet是HttpServlet的子类,与其他的HttpServlet一样,可以通过doService()来响应HTTP请求。然而,依照Spring MVC的使用,业务逻辑的调用入口是在handler的handler函数中实现的,这里是连接Spring MVC和应用业务逻辑实现的地方。DispatcherServlcet的doService的实现如下代码:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
// 对HTTP请求参数进行快照处理
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
// 这个doDispatch是分发请求的入口
doDispatch(request, response);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
对请求的处理实际上是由doDispatch()来完成的,如下代码所示。这个doDispatch方法是DispatcherServlet完成Dispatcher的主要方法,包括准备ModelAndView,调用getHandler来响应HTTP请求,然后通过执行Handler的处理来得到返回的ModelAndView结果,最后把这个ModelAndView对象交给相应的视图对象去呈现。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 这里为试图准备好一个ModelAndView,这个ModelAndView持有handler处理请求的的结果
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 根据请求得到对应的handler,handler的注册以及getHandler的实现
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 这里是实际调用handler的地方,在执行handler之前,用HandlerAdapter先检查
// 一下handler的合法性,是不是按Spring的要求编写的handler
// handler处理的结果封装到ModelAndView对象中,为视图提供展现数据
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
/*
* 通过调用HandleAdapter的handle方法,实际上触发对Controller的
* handleRequest方法的调用
*/
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
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);
}
}
}
我们可以看到和MVC框架紧密相关的代码,比如如何得到和HTTP请求相对应的HandlerExecutionChain,执行handler并把模型数据展现到视图中。这个handler的请求处理过程是一个比较典型的Command模式的应用。在DispatcherServlet中取得handler的过程如下:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 这里是从HandlerMapping中去取handler的调用,与前面对handlerMapping的分析在这里就接上了
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中持有的handlerMapping来生成一个。handlerMapping得到handler的过程会遍历当前持有的所有handlerMapping,因为在DispatcherServlet中可能定义了不止一个handlerMapping。在这一系列的handlerMapping中,只要找到一个需要的handler,就会停止查找,而返回当前已经得到的handler。在找到handler以后,通过handler返回的是一个HandlerExecutionChain对象,其中包含了最终的Controller和定义的一个拦截器链。对于这个过程,在前面对SimpleUrlHandlerMapping的实现中已经分析过了,在那里了解了getHandler是怎样得到一个HandlerExecutionChain的。得到HandlerExecutionChain以后,DispatcherServlet通过HandlerAdapter对这个Handler的合法性进行判断,然后返回适配结果。这个处理代码如下:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 对持有的所有adapter进行匹配
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");
}
通过判断,可以知道这个handler是不是Controller接口的实现,比如可以通过具体HandlerAdapter实现来了解这个适配过程。以SimpleControllerHandlerAdapter的实现为例来了解这个判断是怎样起作用的,如下代码所示。这个判断通过support方法来实现,判断当前的handler是不是Controller对象,如果是,那么返回true,如果不是,那么返回false。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
// 判断将要调用的handler是不是Controller
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
经过上面一系列的处理,得到了handler对象,接着就可以开始调用handler对象中的HTTP响应了。在handler中封装了应用业务逻辑,由这些逻辑对HTTP请求进行相应的处理,生成各种需要的数据,并把这些数据封装到ModelAndView对象中去,这个ModelAndView的数据封装是Spirng MVC框架的要求。对handler来说,这些都是通过调用handler的handleRequest方法来触发完成的。在得到ModelAndView对象以后,这个ModelAndView对象会被交给MVC模式中的视图类,由视图类对ModelAndView对象中的数据进行呈现。视图呈现的调用入口在DispatcherServlet的doDispatcher方法中实现,它的调用入口是render方法。