一:支持的方法分类
支持的方法类型有:@RequestMapping、@InitBinder、@ModelAttribute
其中互斥的:@RequestMapping、@InitBinder、@ModelAttribute
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (isHandlerMethod(specificMethod) &&
(bridgedMethod == specificMethod || !isHandlerMethod(bridgedMethod))) { // 注解 @RequestMapping 类型
handlerMethods.add(specificMethod);
}
else if (isInitBinderMethod(specificMethod) &&
(bridgedMethod == specificMethod || !isInitBinderMethod(bridgedMethod))) { // 注解 @InitBinder 类型
initBinderMethods.add(specificMethod);
}
else if (isModelAttributeMethod(specificMethod) &&
(bridgedMethod == specificMethod || !isModelAttributeMethod(bridgedMethod))) { // 注解 @ModelAttribute 类型
modelAttributeMethods.add(specificMethod);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
分类1:initBinder(声明@InitBinder注解的方法)方法
1、参数支持的注解
参数支持的注解有:@RequestParam、@PathVariable。其中互斥的有:@RequestParam、@PathVariable
参数支持的类型有:WebDataBinder、其他类型
2、返回值支持的注解
@InitBinder 声明的方法不能有返回值
分类2:Handler方法、Model 方法(声明@RequestMapping/@ModelAttribute注解的方法)方法
1、参数支持的注解
方法每个参数可包含的注解有:@RequestParam、@RequestHeader、@RequestBody、@CookieValue、@PathVariable、@ModelAttribute、@Value、@Validated
其中互斥的注解有:@RequestParam、@RequestHeader、@RequestBody、@CookieValue、@PathVariable、@ModelAttribute
for (Annotation paramAnn : paramAnns) {
if (RequestParam.class.isInstance(paramAnn)) { // 从request获取
RequestParam requestParam = (RequestParam) paramAnn;
paramName = requestParam.name();
required = requestParam.required();
defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
annotationsFound++;
}
else if (RequestHeader.class.isInstance(paramAnn)) { // 从header获取
RequestHeader requestHeader = (RequestHeader) paramAnn;
headerName = requestHeader.name();
required = requestHeader.required();
defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
annotationsFound++;
}
else if (RequestBody.class.isInstance(paramAnn)) { // 从body获取
requestBodyFound = true;
annotationsFound++;
}
else if (CookieValue.class.isInstance(paramAnn)) { // 从cookie获取
CookieValue cookieValue = (CookieValue) paramAnn;
cookieName = cookieValue.name();
required = cookieValue.required();
defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
annotationsFound++;
}
else if (PathVariable.class.isInstance(paramAnn)) { // 从path获取
PathVariable pathVar = (PathVariable) paramAnn;
pathVarName = pathVar.value();
annotationsFound++;
}
else if (ModelAttribute.class.isInstance(paramAnn)) { // 从model方法获取
ModelAttribute attr = (ModelAttribute) paramAnn;
attrName = attr.value();
annotationsFound++;
}
else if (Value.class.isInstance(paramAnn)) { // 默认值
defaultValue = ((Value) paramAnn).value();
}
else { // 校验支持
Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class);
if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
validate = true;
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn));
validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
}
}
}
2、返回值支持的注解
。
二:handler方法调用的过程(@ModelAttribute-->@RequestParam--->@InitBinder)
1、调用 @ModelAttribute声明的方法,获取值设置到 implicitModel
2、解析目标方法上的参数
1、迭代各个参数,解析注解
1、@RequestParam、
1、获取《请求参数值》
2、初始化绑定器
1、调用《声明@InitBinder注解的方法》
命中的条件1:检查《属性名有命中 @InitBinder 注解声明的targetNames》
命中的条件2:检查《注解 @InitBinder 没有声明 targetNames》
3、转换《请求参数值》到《目标类型》
2、@RequestHeader、
3、@RequestBody、
4、@CookieValue、
5、@PathVariable、
6、@ModelAttribute、
@ModelAttribute(name="field0")
1、创建指定参数的《目标对象》
2、创建《绑定对象》
3、调用@InitBinder声明的方法列表,初始化《绑定对象》
4、把数据绑定到《目标对象》的指定属性field0
7、@Value、
8、@Validated
@Controller、@RequestMapping路由注解
@Controller // 在类上声明,类里面的方法声明的地址,就是路由地址,本注解即使配置value也不会进行拼接
@RequestMapping(value = "fooOneRequestMappingHandler") // 在类上声明,类里面的方法声明的地址,是路由地址的一部分,本注解配置的value会进行拼接
@RestController // 在类上声明,注解等价 @Controller + @ResponseBody;类里面的方法声明的地址,就是路由地址,本注解即使配置value也不会进行拼接