springmvc 返回 json 内部处理流程

阅读数:60 2019 年 9 月 24 日 14:17

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);
9
10 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 返回 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 // 省略部分代码......
11
12 // 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 // 初始化 handlerMappings
13 initHandlerMappings(context);
14 // 初始化 handlerAdapters
15 initHandlerAdapters(context);
16 initHandlerExceptionResolvers(context);
17 initRequestToViewNameTranslator(context);
18 initViewResolvers(context);
19 initFlashMapManager(context);
20 }
21}

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

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

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

springmvc返回json内部处理流程

HandlerMappings

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

springmvc返回json内部处理流程

HandlerAdapters

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

AbstractHandlerMethodAdapter

DispatcherServlet 中的 handle 方法调用了该类,该类子类实现了 handleInternal 方法。
PS. 该类使用了模板设计模式(该模式在 spring 体系中经常使用)

复制代码
1@Override
2public 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;// 最终返回的为 null
10 }
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);
18
19 }
20
21 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
22 ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
23
24 // 省略部分代码......
25 // 返回的 ModelAndView 为 null
26 if (mavContainer.isRequestHandled()) {
27 return null;
28 }
29 // 省略部分代码......
30 }
31
32}

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

ServletInvocableHandlerMethod

RequestMappingHandlerAdapter 调用了 invokeAndHandle 方法。

复制代码
1public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
2 // 省略部分代码......
3 // 设置 RequestHandled=false
4 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):

springmvc返回json内部处理流程

returnValueHandlers

RequestResponseBodyMethodProcessor 的 supportsReturnType 方法:

复制代码
1@Override
2public boolean supportsReturnType(MethodParameter returnType) {
3 //RequestResponseBodyMethodProcessor 处理注解 ResponseBody
4 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}

springmvc返回json内部处理流程

ssageConverters

结束语

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

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

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

原文链接:

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

评论

发布