文章目录
小知识
- HandlerMapping意思是处理器映射,把一个URL指定到一个Controller上
doGet的实现过程
HttpServlet生命了doGet方法
然后他的子类FrameworkServlet的doGet方法和dopost里面实际上执行的都是processRequest方法
processRequest这个方法里面起主要作用的try里面的哪一行
也就是这里
但是点进去看这玩意是个抽象方法
这个方法的实现在它的子类里面 也就是下面这个
这个子类里面的doservice里面又很多东西 但是都不用看 里面起主要作用的是
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
这里起了主要作用
DispatcherServlet里面的 doDispatch() 是每个请求都会调用的方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
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 = "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;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
细说doDispatch()
我们来看第一个干事的方法
检查是不是文件上传请求
如果是文件上传的话就进行一个转换
看当前请求是那个Handler(我们编写的Controller)去处理请求
发送个GET 请求
我们进入这个 getHandler
这个就是获取请求映射
handerMappings里面都保存了什么?
打断点看一下发送的请求
第一个存放了我们再controller存放的所有映射
后面四个都是系统给我们默认配置的 如果我们自定义的映射处理的话我们也会在这里面找到 关于自定义的我们以后再说
我们很容易就会看到
这不就是我们的欢迎页面吗
来看一下
看一下路径设置
也就是说访问 / 会直接跳转到欢迎页面
也就是这页面
我们再来看这个
这个RequestMappingHandlerMapping保存了所有的@RequestMapping和handler的映射规则
那么它是怎么保存的?
springboot启动的时候会扫描所有的注解
比如说下面这些
然后把这些注解信息都保存到
这个里面
然后去找那个能处理这个请求
我们看看这里面都有什么信息
我们惊奇的看到 这里面写的都是我们自己写的映射
我们自己写的映射都在mappingLookup里面
这是我们自己写的映射
我们可以看到这都是一一对应的 当然我这里只截取了一部分
上面我们已经说过了 一个请求发过来要先遍历去寻找我们要用的controller
那么我们应该怎么去寻找?
这里面的继承关系很复杂 这里就不说了 到最里面实际干活的就是下面这个
getHandlerInternal 去寻找
这里先得到一个路径
然后再整一把🔒 避免并发查询的问题
这个有没有眼熟?
这不就是上面我们发现的放我们写的所有controller的那个地方吗?
我们再进入try里面
看看这个方法在干什么
看一下是怎么找的
现根据url找
看一下找到了什么
因为我们是用rest风格 所有找到了这四个
把所有找到的放到
这个集合里面
要是没找到就放个空
先把找到的符合规则的第一个给放进去
如果找到了很多
就各种排序 然后各种对比之后 就报个错
大概意思是你有几个方法能处理相同的请求
整体代码在下面
if (!matches.isEmpty()) {
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator<AbstractHandlerMethodMapping<T>.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)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
总结
所有的请求映射都在HandlerMapping中。
● SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
● SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
● 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。
○ 如果有就找到这个请求对应的handler
○ 如果没有就是下一个 HandlerMapping