在与同事的一次学习交流中,交流主题为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 方法,该方法主要完成以下四件事情:
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 1112 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 的核心判断逻辑如下:
12@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;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);1819 }2021 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,22 ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {2324 25 26 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 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@Override2public 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 {45 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
评论