AnnotationMethodHandlerAdapter详细分析

1. API类图

在这里插入图片描述

  • ApplicationContextAware

  • ServletContextAware

  • BeanFactoryAware

  • HandlerAdapter

public interface HandlerAdapter {
    boolean supports(Object var1);//判断能否处理Handler

    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;//实际处理请求

    long getLastModified(HttpServletRequest var1, Object var2);
}

2. 初始化

  • 构造方法
public AnnotationMethodHandlerAdapter() {
        super(false);
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        stringHttpMessageConverter.setWriteAcceptCharset(false);
        this.messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()};
}

主要初始化http消息转换器, HttpMessageConverter能根据MIME类型, 进行Java对象和http格式相互转换.

public interface HttpMessageConverter<T> {
    boolean canRead(Class<?> var1, MediaType var2);

    boolean canWrite(Class<?> var1, MediaType var2);

    List<MediaType> getSupportedMediaTypes();

    T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;

    void write(T var1, MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}

其中

ByteArrayHttpMessageConverter: 支持“application/octet-stream“和“*/*"类型的字节转换

StringHttpMessageConverter: 支持“text/plain"和“*/*”类型的字符串转换

SourceHttpMessageConverter: 支持“application/xml“, “text/xml”, "application/**xml"类型进行xml转换

XmlAwareFormHttpMessageConverter: 支持form请求:application/x-www-form-urlencoded和multipart/form-data


3. 处理请求流程

  • boolean supports(Object var1)

参考DispatcherServlet的doDispatch方法(略): 遍历DispatcherServlet的handlerAdapters列表找到第一个support的HandlerAdapter. 源码如下:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        Iterator i$ = this.handlerAdapters.iterator();
        HandlerAdapter ha;
        do {
            if (!i$.hasNext()) {
                throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
            }
            ha = (HandlerAdapter)i$.next();
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Testing handler adapter [" + ha + "]");
            }
        } while(!ha.supports(handler));
        return ha;
    }

那么AnnotationMethodHandlerAdapter的support方法是如何实现的呢?

简而言之, 就是收集@Controller类的元信息并缓存, 如果Handler有@RequestMapping的方法,support返回true

因为刚启动时没有缓存, 所有每个endpoint第一次请求时会有点慢

public boolean supports(Object handler) {
        return this.getMethodResolver(handler).hasHandlerMethods();
}
    
private AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver getMethodResolver(Object handler) {
        Class handlerClass = ClassUtils.getUserClass(handler);
        AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver resolver = (AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver)this.methodResolverCache.get(handlerClass);
        if (resolver == null) {
            synchronized(this.methodResolverCache) {
                resolver = (AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver)this.methodResolverCache.get(handlerClass);
                if (resolver == null) {
                    resolver = new AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver(handlerClass);
                    this.methodResolverCache.put(handlerClass, resolver);
                }
            }
        }
        return resolver;
}

这里需要注意HandlerMethodResolver和ServletHandlerMethodResolver两个类, 其会参与处理请求时选择最佳Method, 处理@InitBind、@ModelAttribute、@PathVariable等变量的绑定等步骤

public class HandlerMethodResolver {
    private final Set<Method> handlerMethods = new LinkedHashSet();//标注@RequestMapping的方法
    private final Set<Method> initBinderMethods = new LinkedHashSet();//标注@InitMethod
    private final Set<Method> modelAttributeMethods = new LinkedHashSet();//标注@ModelAttribute
    private RequestMapping typeLevelMapping;//类上可能的@RquestMapping
    private final Set<String> sessionAttributeNames=new HashSet();//类上@SessionAttributeNames
    private final Set<Class> sessionAttributeTypes = new HashSet();//类上@SessionAttributeTypes
		//略   
 	 public void init(Class<?> handlerType) {
        Set<Class<?>> handlerTypes = new LinkedHashSet();
        Class<?> specificHandlerType = null;
        handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
        Iterator i$ = handlerTypes.iterator();

        while(i$.hasNext()) {
            Class<?> currentHandlerType = (Class)i$.next();
            ReflectionUtils.doWithMethods(currentHandlerType, new MethodCallback() {
                public void doWith(Method method) {
                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    if (!HandlerMethodResolver.this.isHandlerMethod(specificMethod) || bridgedMethod != specificMethod && HandlerMethodResolver.this.isHandlerMethod(bridgedMethod)) {
                        if (HandlerMethodResolver.this.isInitBinderMethod(specificMethod) && (bridgedMethod == specificMethod || !HandlerMethodResolver.this.isInitBinderMethod(bridgedMethod))) {
                            HandlerMethodResolver.this.initBinderMethods.add(specificMethod);
                        } else if (HandlerMethodResolver.this.isModelAttributeMethod(specificMethod) && (bridgedMethod == specificMethod || !HandlerMethodResolver.this.isModelAttributeMethod(bridgedMethod))) {
                            HandlerMethodResolver.this.modelAttributeMethods.add(specificMethod);
                        }
                    } else {
                        HandlerMethodResolver.this.handlerMethods.add(specificMethod);
                    }

                }
            }, ReflectionUtils.USER_DECLARED_METHODS);
        }

        this.typeLevelMapping = (RequestMapping)AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
        SessionAttributes sessionAttributes = (SessionAttributes)AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
        this.sessionAttributesFound = sessionAttributes != null;
        if (this.sessionAttributesFound) {
            this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.value()));
            this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
        }

    }

    protected boolean isHandlerMethod(Method method) {
        return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
    }

    protected boolean isInitBinderMethod(Method method) {
        return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
    }

    protected boolean isModelAttributeMethod(Method method) {
        return AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null;
    }
}
  • ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3)

那么AnnotationMethodHandlerAdapter是怎么实现的呢?

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver methodResolver = this.getMethodResolver(handler);
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        AnnotationMethodHandlerAdapter.ServletHandlerMethodInvoker methodInvoker = new AnnotationMethodHandlerAdapter.ServletHandlerMethodInvoker(methodResolver);
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        ExtendedModelMap implicitModel = new BindingAwareModelMap();
        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
        ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
        methodInvoker.updateModelAttributes(handler, mav != null ? mav.getModel() : null, implicitModel, webRequest);
        return mav;
    }

根据上述源码, 简要流程如下:

  1. 先根据前面的ServletHandlerMethodResolver和request解析出bestMethod

  2. 将Method封装成HandlerMethodInvoker, 并调用方法

    在这各步骤里完成了@RequestMaping方法参数上的所有@RequstParam,@ModelAttribute,@RequestHeader,@RequestBody,@PathVariable等等参数的解析/绑定

  3. 根据返回值处理, 根据Method的相应注解及返回值类型进行顺序性处理

public ModelAndView getModelAndView(Method handlerMethod, Class handlerType, Object returnValue, ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception {
            //1.
            if (returnValue instanceof HttpEntity) {
                this.handleHttpEntityResponse((HttpEntity)returnValue, webRequest);
                return null;
            } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
                this.handleResponseBody(returnValue, webRequest);
                return null;
            } else if (returnValue instanceof ModelAndView) {
                ModelAndView mavx = (ModelAndView)returnValue;
                mavx.getModelMap().mergeAttributes(implicitModel);
                return mavx;
            } else if (returnValue instanceof Model) {
                return (new ModelAndView()).addAllObjects(implicitModel).addAllObjects(((Model)returnValue).asMap());
            } else if (returnValue instanceof View) {
                return (new ModelAndView((View)returnValue)).addAllObjects(implicitModel);
            } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
                this.addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
                return (new ModelAndView()).addAllObjects(implicitModel);
            } else if (returnValue instanceof Map) {
                return (new ModelAndView()).addAllObjects(implicitModel).addAllObjects((Map)returnValue);
            } else if (returnValue instanceof String) {
                return (new ModelAndView((String)returnValue)).addAllObjects(implicitModel);
            } else if (returnValue == null) {
                return !this.responseArgumentUsed && !webRequest.isNotModified() ? (new ModelAndView()).addAllObjects(implicitModel) : null;
            } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) {
                this.addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
                return (new ModelAndView()).addAllObjects(implicitModel);
            } else {
                throw new IllegalArgumentException("Invalid handler method return value: " + returnValue);
            }
        }

其中, 涉及到参数bind和参数校验API设计比较复杂, 有时间再分析.

public class WebDataBinder extends DataBinder {
    public static final String DEFAULT_FIELD_MARKER_PREFIX = "_";
    public static final String DEFAULT_FIELD_DEFAULT_PREFIX = "!";
    private String fieldMarkerPrefix = "_";
    private String fieldDefaultPrefix = "!";
    private boolean bindEmptyMultipartFiles = true;
}    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值