先准备测试需要的控制器类
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "Hello Spring!";
}
}
来看DispatcherServlet的类结构:
它继承了frameworkServlet,我们都知道在浏览器上发出请求,最先到达的是Servlet的doGet()或doPost方法。
DispatcherServlet本身并没有实现这两个方法,于是去他的父类中查找,
找到了对应的方法,它又调用了processRequest的方法。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(frameworkServlet.class.getName(), new frameworkServlet.RequestBindingInterceptor());
this.initContextHolders(request, localeContext, requestAttributes);
try {
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
在processRequest方法中,进行了一堆初始化操作,最后调用doService方法。
frameworkServlet本实的doService是抽象的,DispatcherServlet实现类它。
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
......
RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
ServletRequestPathUtils.parseAndCache(request);
}
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
if (this.parseRequestPath) {
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
}
}
}
在doService方法里,先进行初始化,设置了一堆参数。之后来到了核心语句:
doDispatch
{
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
......
在doDisptach中,我们看到它实例化了一个ModelAndView对象,我们已经知道SpringMVC最终会将我们模型和视图对象封装程ModelAndView对象进行解析。也就是说,分发工作在实例化mv对象之前就已经完成了。
方法中,他还创建了一个mapperHandler对象,从名字来看是映射执行器的意思,通过debug我们发现它是这个样子的
内部包含了我们要执行的方法。所以mapperHandler的创建与初始化就是执行分发的过程。
来到获得mapperHandler的get方法
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
可以看到它会遍历控制器映射,如果不是空的话,就直接返回。先来看一下控制器映射中都有什么。我们首先看到了RequestMappingHandlerMapper,请求映射处理映射。从代码中我们可以看到,最终是将RequestMappingHandlerMapper解析成了控制器执行链。不难猜测,这就是执行对应方法的对象。那么如何获得对应的方法呢。
来到getHandler()方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.obtainApplicationContext().getBean(handlerName);
}
if (!ServletRequestPathUtils.hasCachedPath(request)) {
this.initLookupPath(request);
}
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
.......
return executionChain;
}
}
在方法开始就调用了另外一个方法来获取Object类型的handler,接着往下进入
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
HandlerMethod var2;
try {
var2 = super.getHandlerInternal(request);
} finally {
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
return var2;
}
我们可以看到最终返回了一个HanlerMethod,而他是通过调用父类的同名方法得到的。
来到父类的该方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.initLookupPath(request);
this.mappingRegistry.acquireReadLock();
HandlerMethod var4;
try {
HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
var4 = handlerMethod != null ? handlerMethod.createWithResolvedBean() : null;
} finally {
this.mappingRegistry.releaseReadLock();
}
return var4;
}
它首先获取了一个叫"lookupPath"目标路径的字符串对象。通过debug我们可以看到整个lookupPath正是我们的请求路径。
然后调用另一个方法来返回控制器方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List.Match> matches = new ArrayList();
List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (matches.isEmpty()) {
return this.handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
} else {
AbstractHandlerMethodMapping.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
Iterator var7 = matches.iterator();
while(var7.hasNext()) {
AbstractHandlerMethodMapping.Match match = (AbstractHandlerMethodMapping.Match)var7.next();
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
} else {
AbstractHandlerMethodMapping.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List.Match> matches = new ArrayList();
List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (matches.isEmpty()) {
return this.handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
} else {
AbstractHandlerMethodMapping.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
Iterator var7 = matches.iterator();
while(var7.hasNext()) {
AbstractHandlerMethodMapping.Match match = (AbstractHandlerMethodMapping.Match)var7.next();
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
} else {
AbstractHandlerMethodMapping.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
}
首先从映射注册器里获得了直接匹配对象,最后经过一系列判断,嘴后调用了一个getHandlerMethod方法获得了控制器方法。
public HandlerMethod getHandlerMethod() {
return this.registration.getHandlerMethod();
}
在HandlerMethod类中我们可以看到很多与注解有关的方法
猜测他可能是获得与注解匹配的值后,利用反射来获得我们请求路径对应方法。并加入到执行链中。



