简单总结web
首先请求进入DispatcherServlet 由DispatcherServlet 从HandlerMappings中提取对应的Handler spring
此时只是获取到了对应的Handle,而后得去寻找对应的适配器,即:HandlerAdaptermvc
拿到对应HandlerAdapter时,这时候开始调用对应的Handler处理业务逻辑了(这时候实际上已经执行完了咱们的Controller) 执行完成以后返回一个ModeAndViewapp
这时候交给咱们的ViewResolver经过视图名称查找出对应的视图而后返回ide
最后,渲染视图 返回渲染后的视图 -->响应请求源码分析
首先咱们查看继承关系(关键查看蓝色箭头路线) 会发现DispatcherServlet无非就是一个HttpServletthis
由此,咱们能够去查看Servlet的关键方法:service,doGet,doPost spa
1.service:.net
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}3d
2.doGet:
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
3.doPost:
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
这里会发现不管是哪一个方法最后都调用了processRequest(request, response);咱们把焦点放在这个方法上,会发现一个核心的方法:doService(request, response);而后会发现这个方法有点不同:
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws Exception;
它竟然是一个抽象方法...这就得回到刚刚的继承关系中,找到他的子类了:DispatcherServlet
反正我看到这个方法的实现的时候,脑海里就浮现出4个字:花 里 胡 哨 。代码太多,就不放在笔记里面了,太占地方了.. 为何这样说呢? 由于你看完以后会发现关键在于:doDispatch(request, response);是的,没看错,这一行才是关键!
咱们把视角切入这个方法 (至于代码..仍是不放进来了.. ) 总结一下:
把要用的变量都定义好:好比咱们的ModelAndView以及异常..等等;
下面即将看到的是一个熟悉的陌生人(噢不,关键词)
processedRequest = checkMultipart(request);
"Multipart" 这个关键词好像在哪见过??..让我想一想..(渐渐步入了知识盲区) 哦对!在文件上传的时候!(勉强想起来了。。) 是的,其实这行代码就是判断当前请求是不是一个二进制请求(有没有带文件) 固然 这里只是提一下,并非本文的核心内容。。。(有时间的小伙伴能够本身去了解一下)
好的,如今回到咱们的主题,来看看这个方法:
mappedHandler = getHandler(processedRequest);
看过咱们上面流程图的同窗应该会知道他如今在干吗。 如今来获取咱们的Handler了..从哪获取呢? 从他的HandlerMapping里面获取。
问题1:至于这个HandlerMappings 哪里来的呢
这个等下讨论 咱们先来看看他获取的代码:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
咱们能看见他是在遍历一个handlerMappings
问题2:至于这个handlerMapping是什么呢
是两个咱们不认识的东西,至因而什么,如今说了也不知道,咱们继续往下走,能够看见图片上1188行代码, 他从这个mapping 里面获取了一个handler 若是获取到了 这个方法就走完了, 否则就下一次循环
问题1解释:
咱们先回到刚刚那个问题,这个HandlerMapping 哪里来的呢。 很少说,上图:
咱们在源码包的DispatcherServlet.properties文件下会看见, 他定义了图片里的这些属性。 重点放在方框内,第一个属性,就是咱们刚看见的HandlerMappings, 也就是说 HandlerMappings也就是他本身事先定义好的呢。至于第二个属性,我们待会儿见~
也就是说SpringMVC本身自带了2个HandlerMapping 来供咱们选择 至于 为何要有2个呢? 这时候得启动项目从断点的角度来看看了;
咱们用2种方式来注册Controller 分别是:
1.做为Bean的形式:
@Component("/test")
public class TesrController implements org.springframework.web.servlet.mvc.Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("1");
return null;
}
}
2.以Annotation形式:
@Controller
public class AnnotationController {
@RequestMapping("/test2")
public Object test(){
System.out.println("test");
return null;
}
}
咱们先用Bean的方式来跑:
视角走到咱们的mappedHandler = getHandler(processedRequest);里面
问题2解释:
来,跟着箭头走,咱们发现 咱们以Bean的形式注册的Controller 能够从这个BeanNameUrlHandlerMapping里面获取到对应的Handler ; 这里 咱们是否是对于这个HandlerMapping有了懵懂的了解了?
猜测1:
咱们来猜一下 若是是以Annotation的形式注册的Controller的话 就会被第二个HandlerMapping获取到。 至于对不对 这个问题咱们先留着。
咱们先让代码继续走,会发现 Handler返回出来紧接着会执行下面这个方法,这个方法咱们从流程图中能够了解到,就是在找一个适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
问题3:何为适配器?
咱们先来看看他这个方法里面干了啥:
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");
}
其实能看见他是从一个handlerAdapters属性里面遍历了咱们的适配器 这个handlerAdapters哪来的呢? 跟咱们的HandlerMappings同样 在他的配置文件里面有写,就是咱们刚刚所说的 待会儿见的那个东西~ 很少说,上图:
问题3解释:
至于什么是适配器,咱们结合Handler来说, 就如咱们在最开始的总结时所说的, 一开始只是找到了Handler 如今要执行了,可是有个问题,Handler不止一个, 天然而然对应的执行方式就不一样了, 这时候适配器的概念就出来了:对应不一样的Handler的执行方案。
当找到合适的适配器的时候, 基本上就已经收尾了,由于后面在作了一些判断以后(判断请求类型之类的),就开始执行了你的Handler了,上代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这个mv就是咱们的ModlAndView 其实执行完这一行 咱们的Controller的逻辑已经执行完了, 剩下的就是寻找视图 渲染图的事情了....
咱们这里只是使用了Bean的形式执行了一遍流程 假设使用Annotation呢?
如今咱们来使用Annotation来注册Controller看看。咱们这里只看不一样的地方。
猜测1证实:
首先在这个HandlerMappings这里以前的那个就不行了 这里采用了另一个HandlerMapping 其实也就证实了咱们的猜测1
而后就是到了咱们的适配器了:
这里咱们会看到用的是这个适配器 而咱们的Bean方式注册的Controller 的话 使用的是另外两个适配器来的,至于有什么区别呢? 咱们来看看他执行的时候:
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
咱们的Annotation的形式 是拿到这个handler做为一个HandlerMethod 也就是一个方法对象来执行 这时候咱们看看Bean是什么样子的:
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
由最开始能够看到 咱们若是以Bean的形式注册Controller的话 咱们的实现一个Controller的接口 在这里 他把咱们的handler强制转换为一个Controller来执行了。
总结
其实咱们的SpringMVC关键的概念就在于Handler(处理器) 和Adapter(适配器)
经过一个关键的HandlerMappings 找到合适处理你的Controller的Handler 而后再经过HandlerAdapters找到一个合适的HandlerAdapter 来执行Handler即Controller里面的逻辑。 最后再返回ModlAndView...