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;
}
根据上述源码, 简要流程如下:
-
先根据前面的ServletHandlerMethodResolver和request解析出bestMethod
-
将Method封装成HandlerMethodInvoker, 并调用方法
在这各步骤里完成了@RequestMaping方法参数上的所有@RequstParam,@ModelAttribute,@RequestHeader,@RequestBody,@PathVariable等等参数的解析/绑定
-
根据返回值处理, 根据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;
}