springmvc返回json内部处理流程

2019 年 9 月 24 日

springmvc返回json内部处理流程

在与同事的一次学习交流中,交流主题为springmvc相关内部原理,同事提出ResponseBody注解的解释类是什么??即为何加入该注解后返回的是JSON串,与返回ModelAndView的内部处理逻辑有何不同??于是带着疑问开始了springmvc内部源码的跟踪过程。

在阅读以下内容之前希望大家对springmvc的核心处理逻辑已经有所了解。


编写测试代码


 1@RestController 2@EnableAutoConfiguration 3@ComponentScan 4@SpringBootApplication 5@EnableAsync 6public class BasicApplication { 7 8  private static final Logger logger = LoggerFactory.getLogger(BasicApplication.class); 910  public static void main(String[] args) {11    SpringApplication application = new SpringApplication(BasicApplication.class);12    application.run(args);13  }14  @RequestMapping("/")15  public String index() {16    return "Welcome!";17  }18}
复制代码


源码跟踪


浏览器访问 IP:端口号/


在一步一步介绍源码之前,先来一张 springmvc 处理返回 json 的 UML 序列图:



springmvc 返回 json 处理流程


springmvc 核心处理类 DispatcherServlet


该类的入口方法是 doService,该方法调用 doDispatch 方法,该方法主要完成以下四件事情:


  • 得到Handler,方法getHandler

  • 得到HandlerAdapter,方法getHandlerAdapter

  • 具体请求处理,方法handle

  • 结果处理及异常处理,方法processDispatchResult


 1protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { 2    //省略部分代码...... 3    // 1.从handlerMappings获得HandlerExecutionChain. 4    mappedHandler = getHandler(processedRequest); 5    // 2.获得HandlerAdapter 6    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 7    //省略部分代码...... 8    // 3. 进行具体的请求处理. 9    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());10    //省略部分代码......1112    // 4.结果处理及异常处理13    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);14     //省略部分代码......15}
复制代码


方法 doDispatch 中的 handlerMappings 和 handlerAdapters 又是怎么来的呢??发现是 DispatcherServlet 继承了 FrameworkServlet,覆写了其中 onRefresh 方法,进行 handlerMappings 和 handlerAdapters 的初始化。


 1public class DispatcherServlet extends FrameworkServlet { 2    //DispatcherServlet继承了FrameworkServlet,在系统启动的时候初始化了相关的参数 3        @Override 4    protected void onRefresh(ApplicationContext context) { 5        initStrategies(context); 6    } 7 8        protected void initStrategies(ApplicationContext context) { 9            initMultipartResolver(context);10            initLocaleResolver(context);11            initThemeResolver(context);12            //初始化handlerMappings13            initHandlerMappings(context);14            //初始化handlerAdapters15            initHandlerAdapters(context);16            initHandlerExceptionResolvers(context);17            initRequestToViewNameTranslator(context);18            initViewResolvers(context);19            initFlashMapManager(context);20        }21}
复制代码


在调用 getHandler()和 getHandlerAdapter 时,都进行了相关的判断,如 getHandlerAdapter 的核心判断逻辑如下:


1//得到HandlerAdapter的核心判断方法2@Override3public final boolean supports(Object handler) {4    return (handler instanceof HandlerMethod && supportsInternal(HandlerMethod)handler));5}
复制代码


handlerMappings 初始化值(图中颜色较深的为本例中的 Handler):



HandlerMappings


handlerAdapters 初始化值(图中颜色较深的为本例中的 HandlerAdapter):



HandlerAdapters


在跟踪完 handlerMappings 和 handlerAdapters 之后,我们来查看该方法中的第三步。


AbstractHandlerMethodAdapter


DispatcherServlet 中的 handle 方法调用了该类,该类子类实现了 handleInternal 方法。


PS.该类使用了模板设计模式(该模式在 spring 体系中经常使用)


1@Override2public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)3            throws Exception {4    return handleInternal(request, response, (HandlerMethod) handler);5}
复制代码


RequestMappingHandlerAdapter


RequestMappingHandlerAdapter 继承 AbstractHandlerMethodAdapter,主要包含两个方法:


  • handleInternal

  • invokeHandlerMethod

  • getModelAndView


 1public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter 2        implements BeanFactoryAware, InitializingBean { 3 4        protected ModelAndView handleInternal(HttpServletRequest request, 5            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { 6        //省略部分代码...... 7        mav = invokeHandlerMethod(request, response, handlerMethod); 8        //省略部分代码...... 9            return mav;//最终返回的为null10    }11    //数据绑定、创建模型和视图容器mavContainer、初始化模型等12        protected ModelAndView invokeHandlerMethod(HttpServletRequest request,13            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {14                //省略部分代码......15        invocableMethod.invokeAndHandle(webRequest, mavContainer);16                 //省略部分代码......17        return getModelAndView(mavContainer, modelFactory, webRequest);1819    }2021        private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,22            ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {2324        //省略部分代码......25        //返回的ModelAndView为null26        if (mavContainer.isRequestHandled()) {27            return null;28        }29        //省略部分代码......30 }3132}
复制代码


方法 handleInternal 调用 invokeHandlerMethod,完成 mavContainer 的初始化。


ServletInvocableHandlerMethod


RequestMappingHandlerAdapter 调用了 invokeAndHandle 方法。


1public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {2    //省略部分代码......3    //设置RequestHandled=false4    mavContainer.setRequestHandled(false);5    //省略部分代码......6    this.returnValueHandlers.handleReturnValue(7                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);8}9            //省略部分代码......
复制代码


HandlerMethodReturnValueHandlerComposite


从 HandlerMethodReturnValueHandlerComposite 中得到 HandlerMethodReturnValueHandler,本例中为 RequestResponseBodyMethodProcessor


 1@Override 2public void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 3 4    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); 5    //省略部分代码...... 6    //调用RequestResponseBodyMethodProcessor中的handleReturnValue 7    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); 8} 9private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {10    //省略部分代码......11    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {12        //省略部分代码......13        if (handler.supportsReturnType(returnType)) {14                return handler;15        }16    }17        return null;18}
复制代码


returnValueHandlers 的值(颜色较深的为本例中的 returnValueHandler):



returnValueHandlers


RequestResponseBodyMethodProcessor 的 supportsReturnType 方法:


1@Override2public boolean supportsReturnType(MethodParameter returnType) {3        //RequestResponseBodyMethodProcessor处理注解ResponseBody4    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||5            returnType.hasMethodAnnotation(ResponseBody.class));6}
复制代码


RequestResponseBodyMethodProcessor


1public void handleReturnValue(Object returnValue, MethodParameter returnType,2            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)3            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {4//省略部分代码......5         //重新设置RequestHandled=true,RequestMappingHandlerAdapter中的getModelAndView使用该参数6        mavContainer.setRequestHandled(true);7        //省略部分代码......8        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);9    }
复制代码


AbstractMessageConverterMethodProcessor


 1protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, 2            ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) 3            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { 4    //省略部分代码...... 5    if (outputValue != null) { 6        addContentDispositionHeader(inputMessage, outputMessage); 7        ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage); 8                //省略部分代码...... 9    }10}        
复制代码



ssageConverters


结束语


好了,至此已经结束了 springmvc 的源码跟踪,个人认为最终要的环节在于 returnValueHandlers 的选择,此外 spring 中的模板模式、责任链模式是值得学习借鉴的地方,非常感谢大家的阅读。


作者介绍:


作者天禄(企业代号名),目前负责贝壳找房 java 后台开发的相关工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/BuWVxIY7eB4-5Hp_HwQ7qg


2019 年 9 月 24 日 14:17417

评论

发布
暂无评论
发现更多内容

请简述 JVM 垃圾回收原理

orchid9

第九周学习总结

orchid9

第九周学习总结

Meow

第九周作业

Geek_ce484f

极客大学架构师训练营

架构师训练营 1 期 - 第九周作业(vaik)

行之

极客大学架构师训练营

架构师训练营 2 期 - 第五周总结

Geek_no_one

极客大学架构师训练营

Snowpack - 更快的前端构建工具

曲迪

效率工具 前端 前端工程化 前端进阶

架构师训练营 2 期 - 第5周命题作业

Geek_no_one

极客大学架构师训练营

第五周总结

Griffenliu

训练营第九周作业 2

仲夏

极客大学架构师训练营

第九周作业

Meow

架构师训练营 - 第九周 - 作业一

行者

第九周总结

solike

架构师训练营第九周课后练习

第五周 作业

Geek_9527

数据库工程师整理最常见mysql面试题,每一道都是工作面试经典

小Q

MySQL 数据库 学习 架构 面试

架构师训练营 1 期 - 第九周总结(vaik)

行之

极客大学架构师训练营

极客时间架构 1 期:第 9 周 性能优化(三) - 学习总结

Null

极客时间架构 1 期:第 9 周 性能优化(三) - 命题作业

Null

第五周学习总结

晴空万里

极客大学架构师训练营

第九周作业总结

Geek_ce484f

极客大学架构师训练营

第九周作业

solike

训练营第五周总结

大脸猫

极客大学架构师训练营

第五周作业

Griffenliu

一致性 hash 算法的实现

幸福小子

一致性Hash算法

一致性hash算法

落朽

架构师训练营 - 作业 - 第九周

Max2@12

文件上传踩坑记及文件清理原理探究

比伯

Java 大数据 编程 架构 计算机

常见的负载均衡实现方案

幸福小子

负载均衡架构

Python进阶——如何正确使用魔法方法?(上)

Kaito

Python

五周 - 作业

水浴清风

一致性hash

springmvc返回json内部处理流程-InfoQ