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) {
thi