Handler、HandlerMapping和HandlerAdapter是Spring MVC中重要的组成部分。
Handler
Handler是对请求进行处理的最小单位,一个最典型的Handler即Controller,Handler用于对Request进行处理,同时将最终的处理结果写入Response。Controller中有方法叫handleRequest(),在这里就可以对Request进行处理并返回一个ModelAndView
package hello.test;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelMap modelMap = new ModelMap();
modelMap.put("key", "value");
return new ModelAndView(new MyView(), modelMap);
}
}
HandlerMapping
HandlerMapping中保存请求的URL和handler的关系,同时其中包含了很多的方法用来添加url和handler的键值对或者是根据url的名字检索出相应的handler。
以BeanNameUrlHandlerMapping为例,在初始化阶段Spring会在其中存放扫描出的路径及其对应的处理这个URL的bean
package org.springframework.web.servlet.handler;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.StringUtils;
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
/**
* Checks name and aliases of the given bean for URLs, starting with "/".
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
// 如果发现bean的名字以"/"开头,就默认是作为处理URL的bean,将其保存
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
而在运行阶段,HandlerMapping则负责为DispatcherServlet中的处理逻辑提供根据URL查询出相应的处理这个URL的bean的功能,这个被查出的bean就是对应这个URL的handler。DispatcherServlet这个类中有一个数组变量叫handlerMappings,handlerMappings中保存所有的HandlerMapping,它的值在Spring MVC进行初始化扫描的时候进行填充,包括以下几种类型
- SimpleUrlHandlerMapping
- RequestMappingHandlerMapping
- BeanNameUrlHandlerMapping
- SimpleUrlHandlerMapping
- WelcomePageHandlerMapping
其中在每个HandlerMapping中都有个HandlerMap对象记录所有相应类型的URL和Handler的对应关系
以下是DispatcherServlet.java中获取handler相关的代码
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
以下代码是AbstractUrlHandlerMapping.java的根据URL获取Handler的具体逻辑
@Nullable
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 = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// Pattern match?
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
}
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, 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<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
HandlerAdapter
HandlerAdapter主要用于调用handler对请求进行处理,并返回modelAndView,如果实际使用中没有指定自定义的HandlerAdapter则Spring框架会默认提供一个SimpleControllerHandlerAdapter,以下是SimpleControllerHandlerAdapter的具体实现,可以看到它最主要的是handler()方法,在这个方法中,它利用传入的handler对另外两个参数Request和Response进行了处理,并返回了一个ModelAndView,这个ModelAndView会紧接着被框架的ViewResolver处理。
package org.springframework.web.servlet.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
// support方法用于判断当前的HandlerAdapter是否支持这个Handler
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
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;
}
}
使用HandlerAdapter的逻辑同样在DispatcherServlet类中,这个类同样有一个数组handlerAdapters用于记录所有系统默认或者编程人员自定义的HandlerAdapter,在doDispatch()方法中,已为代码加上中文注释,主要逻辑是先遍历所有的HandlerMapping,从中找到要处理的Handler,接着对Handler进行遍历,从所有HandlerAdapter中找到适合待处理的HandlerAdapter,接着调用HandlerAdapter对Handler进行实际处理。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 获取所有匹配的HandlerAdapter
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 实际进行处理,getHandler()返回一个可以对请求进行处理的Controller对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
...
}
...
}
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
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");
}