在与同事的一次学习交流中,交流主题为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 核心处理类 DispatcherServlet
该类的入口方法是 doService,该方法调用 doDispatch 方法,该方法主要完成以下四件事情:
1protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
2
3
4 mappedHandler = getHandler(processedRequest);
5
6 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
7
8
9 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
10
11
12
13 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
14
15}
复制代码
方法 doDispatch 中的 handlerMappings 和 handlerAdapters 又是怎么来的呢??发现是 DispatcherServlet 继承了 FrameworkServlet,覆写了其中 onRefresh 方法,进行 handlerMappings 和 handlerAdapters 的初始化。
1public class DispatcherServlet extends FrameworkServlet {
2
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
13 initHandlerMappings(context);
14
15 initHandlerAdapters(context);
16 initHandlerExceptionResolvers(context);
17 initRequestToViewNameTranslator(context);
18 initViewResolvers(context);
19 initFlashMapManager(context);
20 }
21}
复制代码
在调用 getHandler()和 getHandlerAdapter 时,都进行了相关的判断,如 getHandlerAdapter 的核心判断逻辑如下:
1
2@Override
3public 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@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;
10 }
11
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
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
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
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@Override
2public boolean supportsReturnType(MethodParameter returnType) {
3
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
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
评论