当前位置:   article > 正文

Spring MVC 源码 - HandlerAdapter 组件(二)之 ServletInvocableHandlerMethod

servletinvocablehandlermethod

HandlerAdapter 组件

HandlerAdapter 组件,处理器的适配器。因为处理器 handler 的类型是 Object 类型,需要有一个调用者来实现 handler 是怎么被执行。Spring 中的处理器的实现多变,比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口,也可以用 @RequestMapping 注解将方法作为一个处理器等,这就导致 Spring MVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器

HandlerAdapter 组件(二)之 ServletInvocableHandlerMethod

本文是接着《HandlerAdapter 组件(一)之 HandlerAdapter》一文来分享 ServletInvocableHandlerMethod 组件。在 HandlerAdapter 执行处理器的过程中,主要的任务还是交由它来完成的。ServletInvocableHandlerMethod 封装 HandlerMethod 处理器对象,它还包含 HandlerMethodArgumentResolver 参数解析器和 HandlerMethodReturnValueHandler 返回值处理器等组件。虽然内容不多,但还是有必要另一篇进行分析。

回顾

先来回顾一下 RequestMappingHandlerAdapter 是如何创建 ServletInvocableHandlerMethod 对象的,可以回到 《HandlerAdapter 组件(一)之 HandlerAdapter》RequestMappingHandlerAdapter 小节下面的 invokeHandlerMethod 方法,如下:

  1. @Nullable
  2. protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
  3. HandlerMethod handlerMethod) throws Exception {
  4. // ... 省略相关代码
  5. // <4> 创建 ServletInvocableHandlerMethod 对象,并设置其相关属性
  6. ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  7. if (this.argumentResolvers != null) {
  8. invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  9. }
  10. if (this.returnValueHandlers != null) {
  11. invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  12. }
  13. invocableMethod.setDataBinderFactory(binderFactory);
  14. invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  15. // ... 省略相关代码
  16. // <9> 执行调用
  17. invocableMethod.invokeAndHandle(webRequest, mavContainer);
  18. // ... 省略相关代码
  19. }
  20. protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
  21. return new ServletInvocableHandlerMethod(handlerMethod);
  22. }
  • HandlerMethod 处理器封装成 ServletInvocableHandlerMethod 对象,然后设置参数解析器和返回值处理器

  • 这里设置了 ServletInvocableHandlerMethod 对象的 resolversparameterNameDiscovererreturnValueHandlers 相关属性

  • 调用invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)方法,执行处理器

类图

ServletInvocableHandlerMethod 的整体类图如下:

依次分析

HandlerMethod

org.springframework.web.method.HandlerMethod,处理器的方法的封装对象

《HandlerMapping 组件(三)之 AbstractHandlerMethodMapping》AbstractHandlerMethodMapping 小节中已经分析过该对象

InvocableHandlerMethod

org.springframework.web.method.support.InvocableHandlerMethod,继承 HandlerMethod 类,可 invoke 调用的 HandlerMethod 实现类。

也就是说,HandlerMethod 只提供了处理器的方法的基本信息,不提供调用逻辑。

  1. public class InvocableHandlerMethod extends HandlerMethod {
  2. /** 无参时的入参,空数组 */
  3. private static final Object[] EMPTY_ARGS = new Object[0];
  4. /** 数据绑定器工厂 */
  5. @Nullable
  6. private WebDataBinderFactory dataBinderFactory;
  7. /** 参数解析器组合对象 */
  8. private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
  9. /** 方法的参数名称发现器 */
  10. private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
  11. }
invokeForRequest

invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) 方法,执行请求,方法如下:

  1. @Nullable
  2. public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  3. Object... providedArgs) throws Exception {
  4. // <1> 解析参数
  5. Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  6. if (logger.isTraceEnabled()) {
  7. logger.trace("Arguments: " + Arrays.toString(args));
  8. }
  9. // <2> 执行调用
  10. return doInvoke(args);
  11. }

调用 getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) 方法,解析方法的参数们,如下:

  1. protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  2. Object... providedArgs) throws Exception {
  3. // 获得方法的参数
  4. MethodParameter[] parameters = getMethodParameters();
  5. // 无参,返回空数组
  6. if (ObjectUtils.isEmpty(parameters)) {
  7. return EMPTY_ARGS;
  8. }
  9. // 将参数解析成对应的类型
  10. Object[] args = new Object[parameters.length];
  11. for (int i = 0; i < parameters.length; i++) {
  12. // 获得当前遍历的 MethodParameter 对象,并设置 parameterNameDiscoverer 到其中
  13. MethodParameter parameter = parameters[i];
  14. parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  15. // <1> 先从 providedArgs 中获得参数。如果获得到,则进入下一个参数的解析,默认情况 providedArgs 不会传参
  16. args[i] = findProvidedArgument(parameter, providedArgs);
  17. if (args[i] != null) {
  18. continue;
  19. }
  20. // <2> 判断 resolvers 是否支持当前的参数解析
  21. if (!this.resolvers.supportsParameter(parameter)) {
  22. throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
  23. }
  24. try {
  25. // 执行解析,解析成功后,则进入下一个参数的解析
  26. args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
  27. }
  28. catch (Exception ex) {
  29. // Leave stack trace for later, exception may actually be resolved and handled...
  30. if (logger.isDebugEnabled()) {
  31. String exMsg = ex.getMessage();
  32. if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
  33. logger.debug(formatArgumentError(parameter, exMsg));
  34. }
  35. }
  36. throw ex;
  37. }
  38. }
  39. return args;
  40. }
  1. 先从 providedArgs 中获得参数。如果获得到,则进入下一个参数的解析。默认情况下,providedArgs 参数不会传递,所以可以暂时先忽略。保证核心逻辑的理解

  1. 判断 argumentResolvers 是否支持当前的参数解析。如果支持,则进行解析。

调用 doInvoke(Object... args) 方法,执行方法的调用,方法如下:

  1. @Nullable
  2. protected Object doInvoke(Object... args) throws Exception {
  3. // <1> 设置方法为可访问
  4. ReflectionUtils.makeAccessible(getBridgedMethod());
  5. try {
  6. // <2> 执行调用
  7. return getBridgedMethod().invoke(getBean(), args);
  8. }
  9. catch (IllegalArgumentException ex) {
  10. assertTargetBean(getBridgedMethod(), getBean(), args);
  11. String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
  12. throw new IllegalStateException(formatInvokeError(text, args), ex);
  13. }
  14. catch (InvocationTargetException ex) {
  15. // Unwrap for HandlerExceptionResolvers ...
  16. Throwable targetException = ex.getTargetException();
  17. if (targetException instanceof RuntimeException) {
  18. throw (RuntimeException) targetException;
  19. }
  20. else if (targetException instanceof Error) {
  21. throw (Error) targetException;
  22. }
  23. else if (targetException instanceof Exception) {
  24. throw (Exception) targetException;
  25. }
  26. else {
  27. throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
  28. }
  29. }
  30. }
  1. 设置方法为可访问

  1. 通过反射执行该方法

注意,这里获取到的 Method 对象可能是桥接方法,桥接方法:如果泛型对象,编译器则会自动生成一个桥接方法(java1.5向后兼容)

ServletInvocableHandlerMethod

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod,继承 InvocableHandlerMethod 类,用于 DispatcherServlet 执行 HandlerMethod 处理器

构造方法
  1. public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
  2. private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");
  3. /** 返回结果处理器组合对象 */
  4. @Nullable
  5. private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
  6. public ServletInvocableHandlerMethod(Object handler, Method method) {
  7. super(handler, method);
  8. }
  9. public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
  10. super(handlerMethod);
  11. }
  12. }
invokeAndHandle

invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) 方法,处理请求,执行处理器,并处理返回结果,方法如下:

  1. public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
  2. // <1> 执行调用
  3. Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  4. // <2> 设置响应状态码
  5. setResponseStatus(webRequest);
  6. // <3> 设置 ModelAndViewContainer 为请求已处理,返回,和 @ResponseStatus 注解相关
  7. if (returnValue == null) {
  8. if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
  9. disableContentCachingIfNecessary(webRequest);
  10. mavContainer.setRequestHandled(true);
  11. return;
  12. }
  13. } else if (StringUtils.hasText(getResponseStatusReason())) {
  14. mavContainer.setRequestHandled(true);
  15. return;
  16. }
  17. // <4> 设置 ModelAndViewContainer 为请求未处理
  18. mavContainer.setRequestHandled(false);
  19. Assert.state(this.returnValueHandlers != null, "No return value handlers");
  20. try {
  21. // <5> 处理返回值
  22. this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  23. } catch (Exception ex) {
  24. if (logger.isTraceEnabled()) {
  25. logger.trace(formatErrorForReturnValue(returnValue), ex);
  26. }
  27. throw ex;
  28. }
  29. }
  1. 调用 InvocableHandlerMethod 父类的 invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) 方法,执行调用

  1. 调用 setResponseStatus(ServletWebRequest webRequest) 设置响应的状态码,方法如下:

  1. private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
  2. // 获得状态码,和 @ResponseStatus 注解相关
  3. HttpStatus status = getResponseStatus();
  4. if (status == null) {
  5. return;
  6. }
  7. // 设置响应的状态码
  8. HttpServletResponse response = webRequest.getResponse();
  9. if (response != null) {
  10. String reason = getResponseStatusReason();
  11. if (StringUtils.hasText(reason)) { // 有 reason ,则设置 status + reason
  12. response.sendError(status.value(), reason);
  13. } else { // 无 reason ,则仅设置 status
  14. response.setStatus(status.value());
  15. }
  16. }
  17. // To be picked up by RedirectView
  18. // 为了 RedirectView ,所以进行设置
  19. webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
  20. }
  1. 设置 ModelAndViewContainer 为请求已处理,返回,和 @ResponseStatus 注解相关

  1. 设置 ModelAndViewContainer 为请求未处理

  1. 调用 HandlerMethodReturnValueHandlerCompositehandleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) 方法,处理返回值。

总结

HandlerAdapter 执行 HandlerMethod 处理器的过程中,会将该处理器封装成 ServletInvocableHandlerMethod 对象,通过该对象来执行处理器。因为 HandlerMethod 处理器里面仅包含了方法的所有信息,如何解析参数、调用对应的方法、以及处理返回结果,它本身并不知道如何去处理,这里 Spring MVC 借助于 ServletInvocableHandlerMethod 对象来进行操作,原理就是通过反射机制执行该方法

其中涉及到的 HandlerMethodArgumentResolver 参数解析器和 HandlerMethodReturnValueHandler 返回值处理器是比较关键的两个组件,在接下来会逐个进行分析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/917118
推荐阅读
相关标签
  

闽ICP备14008679号