要了解业务代码的返回值是如何被框架解析的,就得知道框架如何调用我们写的controller方法。实际上调用我们写的controller代码只是DispatcherServlet处理http请求并返回给前端的其中一个步骤,request处理,寻找对应的controller方法,拿到处理结果并封装,这是一个完整的流程。步骤如下:

DispatcherServlet.doDispatch ->
AbstractHandlerMethodAdapter.handle() ->
RequestMappingHandleAdapter.handleInternal() ->
RequestMappingHandleAdapter.invokeHandlerMethod() -> ServletInvocableHandlerMethod.invokeAndHandle() ->
InvocableHandlerMethod.invokeForRequest() ->
InvocableHandlerMethod.doInvoke() ->
InvocableHandlerMethod.getBridgedMethod().invoke() ->
ServletInvocableHandlerMethod.invokeAndHandle()在调用invokeForRequest 后拿到returnValue -> returnValueHandlers.handleReturnValue() -> HandlerMethodReturnValueHandlerComposite.handleReturnValue() -> HandlerMethodReturnValueHandlerComposite.selectHandler -> RequestResponseBodyMethodProcessor.handleReturnValue()

画成图:
@ResponseBody标记的返回值是如何解析的(更新中) - 图1

DispatcherServlet.doDispatch

DispatcherServlet是spring mvc的核心,在doDispatch方法中,框架从已经解析好的拦截器,controller url的handler中,根据request的url,匹配出相应的HandlerMapping,并获取了HandlerAdapter的封装——HandlerExecutionChain的实例。随后HandlerAdapter开始处理request请求。HandlerAdapter是抽象的接口,具体的实现是在AbstractHandlerMethodAdapter.handle() 方法中

AbstractHandlerMethodAdapter.handle

该方法有三个参数,HttpServletRequest, HttpServletResponse, Object handler。handler实际的类型是HandlerMethod。
HandlerMethod对象来自于前一个方法我们提到的HandlerExecutionChain实例,获取它的主要逻辑在AbstractHandlerMethodMapping的lookupHandlerMethod方法。在这个方法中,框架根据request解析出的url(也就是我们在RequestMapping注解中写的url,例如”user/login”之类的),在mappingRegistry里匹配相应的数据,mappingRegistry就是spring提前处理好的所有url与对应方法信息的映射,里边有个list叫mappingLookup,保存的就是构造好的handlerMethod对象,然后把拿到的对象排个优先级(如果有多个的话),拿到最佳匹配,返回。贴一点代码:

  1. protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
  2. List<Match> matches = new ArrayList<Match>();
  3. //lookupPath就是restful的url
  4. List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
  5. if (directPathMatches != null) {
  6. addMatchingMappings(directPathMatches, matches, request);
  7. }
  8. //...
  9. if (!matches.isEmpty()) {
  10. //如果有多个,排个队
  11. Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
  12. Collections.sort(matches, comparator);
  13. Match bestMatch = matches.get(0);
  14. //...
  15. handleMatch(bestMatch.mapping, lookupPath, request);
  16. return bestMatch.handlerMethod;
  17. }
  18. else {
  19. return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
  20. }
  21. }

回到AbstractHandlerMethodAdapter中,handle方法直接调用handleInternal方法,而handleInternal方法是一个模板方法,留给了子类实现。具体的实现在RequestMappingHandleAdapter 子类中

RequestMappingHandleAdapter.handleInternal

handleInternal方法的核心逻辑,就是调用invokeHandlerMethod方法,获取了ModelAndView对象。

RequestMappingHandleAdapter.invokeHandlerMethod

先通过handlerMethod构造了ServletInvocableHandlerMethod实例,ServletInvocableHandlerMethod实例实际上就是对HandlerMethod功能的扩展,包括了对处理请求的method的封装,对returnValue的封装。是的,终于到我们今天的主题了,对returnValue的处理就是在ServletInvocableHandlerMethod中进行的。贴一点代码:

  1. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
  2. HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  3. ServletWebRequest webRequest = new ServletWebRequest(request, response);
  4. try {
  5. WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
  6. ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
  7. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  8. invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  9. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  10. invocableMethod.setDataBinderFactory(binderFactory);
  11. invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  12. //...
  13. if (asyncManager.hasConcurrentResult()) {
  14. Object result = asyncManager.getConcurrentResult();
  15. mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
  16. asyncManager.clearConcurrentResult();
  17. if (logger.isDebugEnabled()) {
  18. logger.debug("Found concurrent result value [" + result + "]");
  19. }
  20. invocableMethod = invocableMethod.wrapConcurrentResult(result);
  21. }
  22. //在此处,封装好的controller方法对请求进行处理
  23. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  24. if (asyncManager.isConcurrentHandlingStarted()) {
  25. return null;
  26. }
  27. return getModelAndView(mavContainer, modelFactory, webRequest);
  28. }
  29. finally {
  30. webRequest.requestCompleted();
  31. }
  32. }

ServletInvocableHandlerMethod.invokeAndHandle

在invokeAndHandle方法中,对请求的处理逻辑是在父类InvocableHandlerMethod的invokeForRequest方法中。

InvocableHandlerMethod.invokeForRequest

首先,通过request获取方法的参数。逻辑在getMethodArgumentValues方法中。逻辑也比较直接,就是解析一下

  1. private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
  2. Object... providedArgs) throws Exception {
  3. //获取方法参数
  4. MethodParameter[] parameters = getMethodParameters();
  5. Object[] args = new Object[parameters.length];
  6. for (int i = 0; i < parameters.length; i++) {
  7. MethodParameter parameter = parameters[i];
  8. parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  9. //对参数进行类型的转换
  10. GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
  11. args[i] = resolveProvidedArgument(parameter, providedArgs);
  12. if (args[i] != null) {
  13. continue;
  14. }
  15. if (this.argumentResolvers.supportsParameter(parameter)) {
  16. try {
  17. args[i] = this.argumentResolvers.resolveArgument(
  18. parameter, mavContainer, request, this.dataBinderFactory);
  19. continue;
  20. }
  21. catch (Exception ex) {
  22. if (logger.isDebugEnabled()) {
  23. logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
  24. }
  25. throw ex;
  26. }
  27. }
  28. if (args[i] == null) {
  29. String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
  30. throw new IllegalStateException(msg);
  31. }
  32. }
  33. return args;
  34. }