首先,在原生servlet中处理请求的是doget和dopost方法,在spring中处理请求的首先是dispatcherservlet,所以先来到DispatcherServlet源码
发现它继承了FrameworkServlet,这个FrameworkServlet继承了HttpServletBean,说明dispatcherServlet是一个原生servlet,FrameworkServlet继承了HttpServletBean,HttpServletBean继承了HttpServlet,这个 HttpServletBean里面并没有发现处理请求的doXXX方法。所以呢就来FrameworkServlet里面看看
发现里面有各种do方法,这是处理请求的方法,再进入这些方法中发现,都直接或间接调用了processRequest这个方法,那说明处理请求映射就跟她有关
在这个方法里面先是一堆处理请求,然后执行了一个doService方法,这说明这个方法是关键
再找这个doService方法,他是一个抽象方法,说明这时候就要来到DispatcherServlet里面看看这doservice方法
在这个doservice方法里面,又是一大堆,但是在后面执行了一个doDispatch方法
来到doDispatch方法中,在这个方法里就能找到为什么springboot能找到请求映射确定执行那个控制器方法
首先是一堆初始化参数赋值以及检测有没有文件上传模块好做一些处理,通过debug发现都符合条件
然后来到有这么一行注释【Determine handler for the current request.确定处理请求的处理器就控制器方法】的代码上,进去【向下的箭头】
发现哪,这个源码里有一个handlerMappings请求映射,一共五个,通过遍历看那个能处理当前请求。
那五个请求映射:有两个在WebMvcAutoConfiguration已经见过了,反正就是springboot自己配的
0 = {RequestMappingHandlerMapping@7324}
1 = {WelcomePageHandlerMapping@7325}
2 = {BeanNameUrlHandlerMapping@7326}
3 = {RouterFunctionMapping@7327}
4 = {SimpleUrlHandlerMapping@7328}
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;
}
通过debug,首先遍历第一个RequestMappingHandlerMapping@7324,通过工具IDEA的帮助可以在控制台看见这个里面都有什么,发现这个RequestMappingHandlerMapping里面有当前工程全部请求路径和路径对应的处理器方法,一些自己写的和springboot配置的请求映射、控制器方法
在接收到请求后
首先
来到这:确定请求处理的处理器
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
然后进入到getHandler具体执行中
在这里拿到了所有的RequestMappingHandlerMapping,里面是当前项目中的全部请求和控制器映射,有自己的也有springboot的。
这个方法执行就是循环,然后调用这个mapping.getHandler方法处理请求,匹配,看那个能处理当前请求就用哪个RequestMappingHandlerMapping
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; }
然后进入到mapping.getHandler这个方法执行里面
它调用了一个方法,进入这个方法
Object handler = getHandlerInternal(request);
进入到getHandlerInternal方法中
这个方法显示用一个方法对请求做了处理,然后调用了
return super.getHandlerInternal(request);
进入这个方法getHandlerInternal里面
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//拿到请求映射
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
//对拿到的请求路径和请求进行匹配
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
进入到lookupHandlerMethod里面
在这个方法里面对请求路径和已经存在的RequestMappingHandlerMapping进行匹配
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List matches = new ArrayList<>();
//getMappingsByDirectPath这个方法对请求路径和映射做了匹配配对处理
List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
//拿到根据请求路径得到的映射,如果不为空那就执行addMatchingMappings
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
在addMatchingMappings中
首先对拿到的映射数组遍历,根据顺序一个个匹配,看那个合适,就用那个。
具体做匹配工作的是getMatchingMapping,这个就不看了,里面还有很多方法。知道是它起作用就行了
直到找到了可以处理请求的mapping后,就执行add方法,把它加到matcher数组里面
方法执行完毕
在上面方法执行完毕后,就会回到lookupHandlerMethod里面
刚才已经在mapping中找到了能够处理请求的映射并放进了matches数组里面
现在对数组进行判断,很明显数组不为空。
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (!matches.isEmpty()) {}
在上面不为空判断后,有对请求做一些修饰,然后回到getHandlerInternal里面,这个getHandlerInternal执行完回到上面说到的mapping.getHandler方法里
在这个方法里判断有没有映射对应的控制器方法,找到控制器方法,执行完后,就回到了dispatcherServlet里面的getHandler里面
这样的话就算是找到了能处理这个请求路径的方法
最后
然后把handler返回,然后就是完成了请求控制器映射
接下来就是开始之前mvc学习过的控制器执行流程确定拦截器,获取modelandview,渲染视图,然后相应页面
后面也能自己定义HandlerMapping规则,能指定往那个请求下去访问
意思就是自己在框架的基础上再做一个HandlerMapping