上篇博客主要记录了handlerMapping初始化时的一些笔记,这篇主要是调用过程的学习笔记

调用

在调用一个方法的时候,会通过HttpServlet、FrameworkServlet等进行调用,最终会调用到

org.springframework.web.servlet.DispatcherServlet#doDispatch

我们就从这个方法开始记录笔记
在开始之前,有几个概念,先总结说明一下,上篇博客有说到过,声明一个controller的三种方式,这三种方式在调用的时候,是由不同的handlerMapping和handlerAdapter来处理的

实现Controller接口通过BeanNameUrlHandlerMapping来处理通过SimpleControllerHandlerAdapter来处理通过SimpleControllerHandlerAdapter类中的方法来调用实现接口的目标类的方法实现HttpRequestHandler接口通过BeanNameurlHandlerMapping来处理通过HttpRequestHandlerAdapter来处理通过HttpRequestHandlerAdapter调用实现接口类的目标方法通过@Componenet注解通过RequestMappingHandlerMapping来处理通过RequestMappingHandlerAdappter来处理通过反射的方式来调用目标方法(org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal)

这是三种声明controller的方式对应的处理类和方式

下面是doDispatch()的部分代码

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;
}// Determine handler adapter for the current request.
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.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

我只截取了doDispatch()方法中的部分代码

handlerMapping

这里可以看到:mappedHandler = getHandler(processedRequest);
这个方法是根据request的url找到当前url对应的method是在哪个handlerMapping中存储的,找到了,就返回当前handlerMapping

我们通常所说的:通过url找到对应的handlerMapping就是根据url从map集合中找对应的handlerMapping,在查找的时候,会遍历所有的handlerMapping(spring自己的+程序员提供的),在哪个handlerMapping找到了,就返回哪个handlerMapping
这里不同的handlerMapping,是放在不同的map集合中存储的;在这个遍历之后,找到合适的handlerMapping之后,会将合适的handlerMapping包装成HandlerExecutionChain;

handlerAdapter

根据handlerMapping找合适的handlerAdapter,是指:判断当前的handler(handler我觉得可以简单理解为controller)需要用哪个handlerAdapter来处理;
实现Controller接口的类,需要SimpleControllerHandlerAdapter来处理,在SimpleControllerHandlerAdapter该类中,判断条件很简单:return handler instanceof Controller;

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#supports
@Override
public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);
}

对于HttpRequestHandlerAdapter来说,判断当前handler是否是HttpRequestHandler类型的

@Override
public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);
}

对于RequestMappingHandlerMapping来说

// 只有这里的handler是handlerMethod的实例,就可以了,后面的supportsInternal默认是返回true的
@Override
public final boolean supports(Object handler) {return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

springmvc提供的扩展点

所以这里:spring做的比较好,spring定义了handlerAdapter接口,分别声明了

// 这个方法是判断当前handlerAdapter是否支持handler的处理
boolean supports(Object handler);
//具体处理handler的方法
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

这样就给程序员提供了扩展的空间,程序员如果要自己扩展handlerAdapter,那只需要提供handlerAdapter的实现类即可,并且将自己实现的类告诉spring;spring本身的代码无需做改造,因为在判断使用哪个handlerAdapter的时候,会遍历所有的

调用目标方法

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

是真正来调用目标方法的入口
在调用的时候,如果是通过@Controller注解和@RequestMapping来声明的方法,是通过反射机制来调用的
如果是通过剩下两种方式声明的controller,是直接通过类型强转,调用实现类的方法的
ha.handler()方法其实调用的,就是handlerAdapter实现类中的handler()方法

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#handle@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response);return null;
}
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#handle@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);
}

这两个handlerAdapter的handler方法比较简单,都是直接进行了强转,然后调用相应的实现类中的方法

比较麻烦的是RequestMappingHandlerAdapter的handler方法
这里涉及到从request中取参数赋值,然后通过反射机制,调用method.invoke()方法完成调用
并且还会涉及到对返回值的处理:是通过流写出去?还是进行视图渲染、视图转发等;如果方法加了@ResponseBody注解,就会把返回值通过流的方式写出去;如果没有,那默认是按照modelAndView来进行视图的渲染和返回;
这种处理方式中,给参数赋值的这块逻辑我还在看,待学习之后,补充

springmvc源码-调用相关推荐

  1. SpringMVC源码系列:HandlerMapping

    SpringMVC源码系列:HandlerMapping SpringMVC源码系列:AbstractHandlerMapping HandlerMapping接口是用来查找Handler的.在Spr ...

  2. SpringMVC源码阅读:过滤器

    SpringMVC源码阅读:过滤器 目录 1.前言 2.源码分析 3.自定义过滤器 3.1 自定义过滤器继承OncePerRequestFilter 3.2 自定义过滤器实现Filter接口 4.过滤 ...

  3. SpringMVC源码分析(4)剖析DispatcherServlet重要组件

    简单介绍了一个请求的处理过程, 简略描述了调用过程,并没有涉及过多细节,如url匹配,报文解析转换等. <SpringMVC源码分析(2)DispatcherServlet的初始化>:介绍 ...

  4. springMvc源码刨析笔记

    springMvc源码刨析笔记 MVC 全名是 Model View Controller,是 模型(model)-视图(view)-控制器(controller) 的缩写, 是⼀种⽤于设计创建 We ...

  5. java注解返回不同消息,SpringMVC源码剖析5:消息转换器HttpMessageConverter与@ResponseBody注解...

    转自 [SpringMVC关于json.xml自动转换的原理研究[附带源码分析]](https://www.cnblogs.com/fangj... 部分代码会放在我的的Github:https:// ...

  6. 筑基期第一式:SpringMVC源码解析

    文章目录 SpringMVC源码解析 SPI机制 案例 SpringMVC中SPI的使用 初始化IOC容器与九大组件 初始化容器 初始化九大组件 小结 SpringMVC如何处理一个请求 doDisp ...

  7. springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod

    在之前一篇博客中 springMVC源码分析--RequestMappingHandlerAdapter(五)我们已经简单的介绍到具体请求访问的执行某个Controller中的方法是在RequestM ...

  8. 简单直接让你也读懂springmvc源码分析(3.1)-- HandlerMethodReturnValueHandler

    该源码分析系列文章分如下章节: springmvc源码分析(1)-- DispatcherServlet springmvc源码分析(2)-- HandlerMapping springmvc源码分析 ...

  9. SpringMVC源码剖析(五)-消息转换器HttpMessageConverter

    概述 在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新 ...

  10. SpringMVC源码探究软件六合网站制作(一)----初始化源码

    随着软件 , 开发技术的持续发展,框架技术层出不穷.还是那句话,任何框架技术都是对基础技术的封装.所以,真正要学好用好一个框架,研究其源码都是最直接最有效的途径. 随着Spring技术体系的强势发展, ...

最新文章

  1. flask_sqlalchemy 教程
  2. 英伟达奔驰共同发布自动驾驶系统,还自带停车功能
  3. 一款遥控器拆解之后可利用的元器件
  4. windows winrar 指令_【转】winrar命令行详解
  5. java一个源文件供一个程序_java02 Java源文件范例提供了一个布局合理的Java程序范例 - 下载 - 搜珍网...
  6. 阿里年薪40万老人简历:83岁精通网购,62岁会H5、PS
  7. Linux 抓包工具:tcpdump
  8. openlayers事件类型
  9. 华为哪个是鸿蒙,华为系统是鸿蒙还是安卓?有什么区别
  10. android 中解析json格式数据
  11. HashMap深度解析
  12. 使用jQuery+huandlebars遍历中if判断
  13. VMware14安装步骤
  14. matlab在常微分方程的应用,Matlab在常微分方程教学中的应用
  15. narwal机器人_Narwal云鲸扫地机器人扫拖彻底,用户用得更省心省力
  16. UE4 Slate四 SlateUI如何做动画
  17. 1、学生如何购买云服务器、域名(系列:个人博客搭建)
  18. sklearn基础篇(三)-- 鸢尾花(iris)数据集分析和分类
  19. anki服务端存储迁移
  20. NRF52832学习笔记(39)——设备信息服务(DIS)

热门文章

  1. 时间序列的分析和预测ARIMA
  2. 卷积神经网络CNN:Tensorflow实现(以及对卷积特征的可视化)
  3. 自动驾驶7-2 最终项目概述 Final Project Overview
  4. k-means 及其改进 数库
  5. DSSM核心思想是把查询文本(query)和内容文本(doc)映射到同维度的语义空间中, 以最优化查询文本和内容文本的语义向量之间的余弦相似度为目的
  6. 593. 有效的正方形
  7. 数中唯一只出现一次的数字
  8. 个税倒推收入的计算器_手把手教你做个税计算器(1)
  9. Spring boot initialization failed for https://start.spring.io
  10. 计算机图形学完整笔记(四):消隐