在上一篇的博客中,我提到了关于HandlerMapping的作用。在原书中作者是这样定义它的。每一个HandlerMapping可以持有一系列从URL请求到Controller的映射。在每一个HandlerMapping中都定义了一个map来持有这一系列的映射关系。在这个方法的定义中,通过解析request请求获取其中请求的URL路径,然后找到对应的handler对象,将这个对象封装到HandlerExecutionChain中进行返回。
1.HandlerMapping的配置以及HandlerExecutionChain的实现
首先来看HandlerExecutionChain这个类
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
这个里面定义了handler也就是HTTP请求对应的Controller对象以及一系列的拦截器。还提供了一系列和拦截器有关的维护工作。
例如这里面的addInterceptor(HandlerInterceptor)方法等等。
这个里面定义的Handler和Interceptor需要在定义HandlerMapping时配置好。在SimpleUrlHandlerMapping类中就有一个urlMap来实现匹配HTTP请求。
private final Map<String, Object> urlMap = new LinkedHashMap<String, Object>();
那么这个urlMap是在什么时候进行配置的呢?
来看这两个方法
public void setMappings(Properties mappings) {
CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
}
public void setUrlMap(Map<String, ?> urlMap) {
this.urlMap.putAll(urlMap);
}
之后就是将对应的信息注册到Handler
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
首先是对容器的回调,调用包含有handler对象的容器。接着就是将这些handler注册到urlMap中。
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.
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 {
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
这个方法里面涉及到了对url映射的处理。包括对"/" 和 "/*”的处理
在SimpleUrlHandlerMapping的父类AbstractUrlHandlerMapping中维护了一个
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
这个handlerMap对象配置完毕后,就已经为Spring MVC响应HTTP请求准备好了基本的映射数据。
2.使用HandlerMapping完成请求的映射过程
具体的请求处理是是由getHandler方法来实现的。该方法会根据在设置好的handlerMap来返回相应的请求。
在AbstractHandlerMapping类中实现了这个方法。
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);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
这个方法将取得handler对象和拦截器结合在一起
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
具体的获取handler对象是在getHandlerExecutionChain中完成的
首先从request中得到请求的URL路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
之后根据这个lookupHandler在handlerMap中对handler进行检索并返回
Object handler = lookupHandler(lookupPath, request);
经过这一系列对Http请求进行解析和匹配的过程,得到了与请求对应的handler处理器。但是Spring MVC如何将HTTP请求对应到相应的handler我们还不了解。这中间还要进行一些准备工作。
下一篇博客我将讲述请求如何实现分发,从而到达对应的handler。