上文中提到在DispatcherServlet.doDispatch()方法中,通过getHandler()方法获取HandlerExecutionChain对象(处理器执行链)
那么接下来就讲一讲这个方法:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator var2 = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if (!var2.hasNext()) {
return null;
}
HandlerMapping hm = (HandlerMapping)var2.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
getHandler()涉及一个设计模式——拦截过滤器模式,它会从List<HandlerMapping> handlerMappings中遍历查找对应的HandlerMapping对象,并由HandlerMapping对象创建HandlerExecutionChain对象。List<HandlerMapping> handlerMappings是初始化时在initStrategies()方法中完成的(在上一篇DispatcherServlet的初始化过程 提到过)
HandlerMapping的getHandler()方法是一个接口
实现类为AbstractHandlerMapping.class
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求查找对应的handler
Object handler = this.getHandlerInternal(request);
if (handler == null) {
// 没有找到,则会使用getDefaultHandler()方法获取默认的处理器
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
this.getHandlerInternal(request);是一个抽象方法,实现类为:AbstractUrlHandlerMapping.class
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求路径
String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
// 查找handler
Object handler = this.lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = this.getRootHandler();
}
if (rawHandler == null) {
rawHandler = this.getDefaultHandler();
}
if (rawHandler != null) {
if (rawHandler instanceof String) {
String handlerName = (String)rawHandler;
rawHandler = this.getApplicationContext().getBean(handlerName);
}
this.validateHandler(rawHandler, request);
handler = this.buildPathExposingHandler(rawHandler, lookupPath, lookupPath, (Map)null);
}
}
if (handler != null && this.logger.isDebugEnabled()) {
this.logger.debug("Mapping [" + lookupPath + "] to " + handler);
} else if (handler == null && this.logger.isTraceEnabled()) {
this.logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
进入lookupHandler()可以发现,是通过请求路径字符串在handlerMap中查找到handler
private final Map<String, Object> handlerMap = new LinkedHashMap();
Object handler = this.handlerMap.get(urlPath);
但是当使用RESTful风格的请求地址时,比如请求这个方法时的url为 http://localhost:8080/spring-learn/hello/hls
在handlerMap中将会找不到以/hello/hls为键名的handler:
此时将进行其他方式的匹配:
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.getApplicationContext().getBean(handlerName);
}
this.validateHandler(handler, request);
return this.buildPathExposingHandler(handler, urlPath, urlPath, (Map)null);
} else {
List<String> matchingPatterns = new ArrayList();
Iterator var5 = this.handlerMap.keySet().iterator();
while(var5.hasNext()) {
String registeredPattern = (String)var5.next();
if (this.getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
} else if (this.useTrailingSlashMatch() && !registeredPattern.endsWith("/") && this.getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
String bestPatternMatch = null;
Comparator<String> patternComparator = this.getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestPatternMatch = (String)matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
if (handler == null) {
Assert.isTrue(bestPatternMatch.endsWith("/"));
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
}
String pathWithinMapping;
if (handler instanceof String) {
pathWithinMapping = (String)handler;
handler = this.getApplicationContext().getBean(pathWithinMapping);
}
this.validateHandler(handler, request);
pathWithinMapping = this.getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
Map<String, String> uriTemplateVariables = new LinkedHashMap();
Iterator var9 = matchingPatterns.iterator();
while(var9.hasNext()) {
String matchingPattern = (String)var9.next();
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = this.getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = this.getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return this.buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
} else {
return null;
}
}
}
回到AbstractHandlerMapping.class的getHandler()方法中, getHandlerExecutionChain()方法匹配拦截器然后把上边找到handler整合为一个 HandlerExecutionChain对象
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
Iterator var5 = this.adaptedInterceptors.iterator();
while(var5.hasNext()) {
HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
从getHandlerExecutionChain()方法实现可以看到,首先会判断根据请求获取的处理器是不是HandlerExecutionChain对象。如果是,则直接使用;如果不是,则通过请求处理器Handler创建一个HandlerExecutionChain对象,然后将多个拦截器对象保存到HandlerExecutionChain对象中的List<HandlerInterceptor> interceptorList属性中。因此HandlerExecutionChain封装了请求的处理程序(即Controller中的处理方法)和相关的拦截器
返回到DispatcherServlet类的doDispatch()方法,执行完getHandler()方法以后,得到的HandlerExecutionChain对象如果为空,则会执行noHandlerFound()方法,执行完后直接返回,流程结束。noHandlerFound()方法的代码如下:
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
if (this.throwExceptionIfNoHandlerFound) {
throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
} else {
// 返回404
response.sendError(404);
}
}
如果不为空则继续执行下面的代码。