------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------

先放一张图

很熟悉啊,之前就看过,我们之前已经把handlerMapping剖了个底朝天,顺着上次的进度,继续跟,把HandlerAdapter处理器适配器剖一下

它同样是由中央调度器DispatcherServlet调度到的,所以,还是这个类中找doDispatch(request,response)这个方法,我把有用的代码,扒下来

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 err = null;
Exception dispatchException = null; try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
} //上面的是我说的HandleMapping的执行 流程 //所以从后面的第一行开始看 HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
HandlerExecutionChain mappedHandler这个变量,是处理器执行链,它的getHandler方法,就是获取它里面的处理器
它外面的this.getHandlerAdpter
点过去追踪
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//迭代器
Iterator var2 = this.handlerAdapters.iterator();
//一会要返回去的适配器对象
HandlerAdapter ha;
do {
//如果没有下一个的话。就抛异常
if(!var2.hasNext()) {
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
//将此强转成为处理器适配器
ha = (HandlerAdapter)var2.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler adapter [" + ha + "]");
}
} while(!ha.supports(handler));
//这儿有个适配器模式
return ha;
}

这是下载源码后的最直观的源码

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
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");
}

看ha.sipports(handler)这个方法

找到HandlerAdapter接口

public interface HandlerAdapter {

    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);

}

再来看一下自己写的控制器实现了Controller。这样就看DispatcherServlet属性中的HandlerApater谁支持Controller类型的处理器了。在运行的过程中发现SimpleControllerHandlerAdapter是支持Controller类型的控制器的。
来看一下SimpleControllerHandlerAdapter的代码

找它的实现类:Ctrl+H      SimpleControllerHandlerAdapter

public class SimpleControllerHandlerAdapter implements HandlerAdapter {  

    public boolean supports(Object handler) {
return (handler instanceof Controller);
} public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { return ((Controller) handler).handleRequest(request, response);
} public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
} }

它support来判断是否是处理器

拿到处理器在中央调度器一处调用了handle方法

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
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()); //就是上面这处

看看handle方法,因为被执行调用到,它返回ModelAndView

里面return走的handleRequest是Controller接口的,找它的实现类

AbstractController抽象类,它有实现handleRequest

    @Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception { // Delegate to WebContentGenerator for checking and preparing.
checkRequest(request);
prepareResponse(response); // Execute handleRequestInternal in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);
}
}
} return handleRequestInternal(request, response);
}

看到最后面的那个返回值了吗?是ModelAndView对象,它调用了handleRequestInternal(request,respone)这个方法

还记得AbstractController的实现类吗?不是有种处理器的定义方法就是继承AbstractController

package cn.dawn.day04abstractController;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* Created by Dawn on 2018/3/19.
*/
//处理器
public class FirstController extends AbstractController { protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView me=new ModelAndView();
me.setViewName("index");
return me;
}
}

它的实现类默认要求必须实现handleRequestInternal(request,response)这个方法

所以,理清了吧,再一步步return回去,最后回到了中央调度器

结论,中央处理器DispatcherServlet通过处理器执行链找到handlerAdapter处理器适配器,后者调度了它的处理器,通过处理器处理,返回一个ModelAndView模型和视图对象,一路返回,到中央调度器

 

SSM-SpringMVC-17:SpringMVC中深度剖析HandlerAdapter处理器适配器底层的更多相关文章

  1. 零基础学习java------38---------spring中关于通知类型的补充,springmvc,springmvc入门程序,访问保护资源,参数的绑定(简单数据类型,POJO,包装类),返回数据类型,三大组件,注解

    一. 通知类型 spring aop通知(advice)分成五类: (1)前置通知[Before advice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常. (2)正常返回通知 ...

  2. SpringMVC学习--springmvc原理

    简介 springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合.springmvc是一个基于mvc的web框架. spring的结构图: mvc在b/ ...

  3. springmvc(一) springmvc框架原理分析和简单入门程序

    springmvc这个框架真的非常简单,感觉比struts2还更简单,好好沉淀下来学习~ --WH 一.什么是springmvc? 我们知道三层架构的思想,并且如果你知道ssh的话,就会更加透彻的理解 ...

  4. SSM:spring+springmvc+mybatis框架中的XML配置文件功能详细解释(转)

    原文:https://blog.csdn.net/yijiemamin/article/details/51156189# 这几天一直在整合SSM框架,虽然网上有很多已经整合好的,但是对于里面的配置文 ...

  5. 0927-转载:SSM:spring+springmvc+mybatis框架中的XML配置文件功能详细解释

    这篇文章暂时只对框架中所要用到的配置文件进行解释说明,而且是针对注解形式的,框架运转的具体流程过两天再进行总结. spring+springmvc+mybatis框架中用到了三个XML配置文件:web ...

  6. SSM:spring+springmvc+mybatis框架中的XML配置文件功能详细解释

    这几天一直在整合SSM框架,虽然网上有很多已经整合好的,但是对于里面的配置文件并没有进行过多的说明,很多人知其然不知其所以然,经过几天的搜索和整理,今天总算对其中的XML配置文件有了一定的了解,所以拿 ...

  7. 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二)(代码篇)

    这篇是上一篇的延续: 用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 源代码在github上可以下载,地址:https://github.com/guoxia ...

  8. Maven+SSM框架(Spring+SpringMVC+MyBatis) - Hello World(转发)

    [JSP]Maven+SSM框架(Spring+SpringMVC+MyBatis) - Hello World 来源:http://blog.csdn.net/zhshulin/article/de ...

  9. SSM(Spring+SpringMVC+MyBatis)高并发优化思路

    SSM(Spring+SpringMVC+MyBatis)框架集由Spring.MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容).常作为数据源较简单的web项目的框架 ...

随机推荐

  1. 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  2. Linux:进程通信之消息队列Message实例

    /*send.c*/ /*send.c*/ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h&g ...

  3. ERP-非财务人员的财务培训教(一.一)------基本会计知识

    一.基本会计知识 第一节 会计是企业的语言 反映企业经济状况的两组会计语言词汇 四个层次的会计语言规则 财务会计报告的组成 会计语言要素 会计工作主要是把企业杂乱的会计数据归纳整理,加工编制成有用的财 ...

  4. how tomcat works 5 servlet容器 下

    上一节,我们主要说的是Wrapper容器,这一节我们说Context容器. 再重申一遍,一个Context容器可以包含多个Wrapper容器; 一个Wrapper容器就表示一个独立的servlet. ...

  5. mybatis源码之StatementHandler

    /** * @author Clinton Begin */ public interface StatementHandler { Statement prepare(Connection conn ...

  6. 简单开发Apple Watch的步骤

    好久没写博客了,自己这两年自从孩子出世,也慢慢懈怠了.实在有点对不住了,换了个新公司,也有点时间可以写写东西了.  前几天苹果刚刚发布Apple Watch,Xcode6也更新了watchKit,正好 ...

  7. 在java中读取配置文件信息

    public class PropertyUtil { public static final Properties PROP = new Properties(); /** * 读取配置文件的内容( ...

  8. 解决Visual Studio 2017隐藏“高级保存选项”命令

    Visual Studio提供高级保存选项功能,它能指定特定代码文件的编码规范和行尾所使用的换行符.在Visual Studio 2017中,该命令没有默认显示在“文件”菜单中.用户需要手工设置,才能 ...

  9. Java小技巧输出26个英文字母

    相信有的童鞋写到过与字母有关的小东西,是否有写过全部的字母呢?26个这么多字母,一个个打会疯掉.所有咱们可以用一个小技巧使用for循环帮我们把26个字母自动搞出来,大家来瞅一眼把! 使用Java遍历2 ...

  10. Mac环境svn的使用

    在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...