文章目录
组件
HandlerMethodArgumentResolverComposite
适配方法参数解析器组件,保存所有参数解析器
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
// 持有的参数解析器
private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
// 缓存解析过的参数解析器
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<>(256);
}
HandlerMethodArgumentResolver
方法参数解析器,将request中数据解析为方法参数
public interface HandlerMethodArgumentResolver {
// 判断是否支持方法参数解析
boolean supportsParameter(MethodParameter parameter);
// 解析参数
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
MethodParameter
处理器中的方法参数描述
public class MethodParameter {
// 参数属于的方法
private final Executable executable;
// 参数在方法中的位置
private final int parameterIndex;
@Nullable
private volatile Parameter parameter;
// 参数类型
private volatile Class<?> parameterType;
}
NamedValueInfo
表示有关命名值的信息
protected static class NamedValueInfo {
// 参数名
private final String name;
// 是否必要
private final boolean required;
// 默认值
@Nullable
private final String defaultValue;
}
DataBinder
允许在target上设置属性值的绑定器,包括对验证和绑定结果分析的支持。
public class DataBinder implements PropertyEditorRegistry, TypeConverter {
// 目标对象
private final Object target;
// 对象名
private final String objectName;
}
参数处理流程
- 处理@InitBinder(用于数据绑定、设置数据转换器)注解的方法,先从缓存获取,从全局获取,从当前类获取,最后返回
InitBinderDataBinderFactory
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
// 获得处理方法类型
Class<?> handlerType = handlerMethod.getBeanType();
// 从适配器缓存获取
Set<Method> methods = this.initBinderCache.get(handlerType);
if (methods == null) {
// 缓存无则将当前类@InitBinder修饰的方法加入缓存
methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
// @ControllerAdvice修饰中全局添加
this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
initBinderMethods.add(createInitBinderMethod(bean, method));
}
}
});
// 添加当前类中的@InitBinder方法
for (Method method : methods) {
Object bean = handlerMethod.getBean();
initBinderMethods.add(createInitBinderMethod(bean, method));
}
// 返回InitBinderDataBinderFactory
return createDataBinderFactory(initBinderMethods);
}
- 处理注解@ModelAttribute(用于将方法的参数或方法的返回值绑定到指定的模型属性上)相关内容(@SessionAttributes,@ControllerAdvice),将该注解修饰的方法放入当前适配器缓存,返回的ModelFactory持有了@SessionAttributes处理器和上一步生成的InitBinderDataBinderFactory
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
// 从适配器获得@SessionAttributes处理器
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
// 实际处理器类型
Class<?> handlerType = handlerMethod.getBeanType();
// 从适配器获得@ModelAttribute的缓存
Set<Method> methods = this.modelAttributeCache.get(handlerType);
// 如果为空
if (methods == null) {
// 遍历实际处理器类,获得非@RequestMapper且有@ModelAttribute注解的方法
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
// 放入缓存
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
// 从被@ControllerAdvice修饰的类中获取全局的@ModelAttribute方法
this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
// 获得当前处理器中获得@ModelAttribute方法
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
- invokeHandlerMethod方法中为模型赋值语句,重定向属性FlashMap,SessionAttribute中获取值,ModelAttribute中获取值(调用invokeForRequest方法反射执行@ModelAttribute修饰的方法)
// 从request中获取重定向参数FlashMap存入Model
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 初始模型数据
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 重定向时忽略默认Model,该值默认为false
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 初始模型数据
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
throws Exception {
// 从请求中获取session属性
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
// 放入Model中
container.mergeAttributes(sessionAttributes);
// 调用@ModelAttribute修饰的方法,传入model中
invokeModelAttributeMethods(request, container);
// 遍历sessionAttribute属性给model赋值
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!container.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
}
container.addAttribute(name, value);
}
}
}
// 调用ModelAttribute修饰的方法,将属性值赋值给container中的Model
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
throws Exception {
// 当前ModelFactory中的方法不为空
while (!this.modelMethods.isEmpty()) {
// 从ModelMethod中获取名称不在container中的方法
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
Assert.state(ann != null, "No ModelAttribute annotation");
// 如果容器中已存在ModelAttribute修饰的属性
if (container.containsAttribute(ann.name())) {
// 是否禁用数据绑定
if (!ann.binding()) {
container.setBindingDisabled(ann.name());
}
continue;
}
// 调用invokeForRequest方法获得注解对应方法的返回值
Object returnValue = modelMethod.invokeForRequest(request, container);
// 如果方法返回类型不为空
if (!modelMethod.isVoid()){
// 获得属性名称,如果注解设置的value使用value,否则为返回类型小写
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!ann.binding()) {
container.setBindingDisabled(returnValueName);
}
if (!container.containsAttribute(returnValueName)) {
// 为model添加属性
container.addAttribute(returnValueName, returnValue);
}
}
}
}
- 获取当前方法的参数,方法参数为空直接返回,遍历解析:如providedArgs已提供则continue,否则调用参数解析器解析(从缓存找,未找到则遍历参数解析器集合寻找合适的参数解析器)
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获得当前处理方法的参数
MethodParameter[] parameters = getMethodParameters();
// 为null返回空值
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
// 存放方法参数
Object[] args = new Object[parameters.length];
// 遍历解析参数
for (int i = 0; i < parameters.length; i++) {
// 按顺序获得方法参数
MethodParameter parameter = parameters[i];
// 设置参数名查找器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 从提供的参数搜索
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 所有参数解析器都不支持抛出异常
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 从缓存找,未找到遍历参数解析器,调用参数解析器的resolveArgument方法
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
···抛出异常
}
return args;
}
- 参数解析器解析参数,以RequestParamMethodArgumentResolver为例,实例调用的是AbstractNamedValueMethodArgumentResolver中的resolveArgument方法。首先根据方法参数获得命名值信息,然后解析命名值(存在占位符的参数名),根据参数名从请求中获取参数值,处理参数值为空的情况,最后处理@InitBinder进行数据绑定和转换
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 获得参数命名值信息(参数对应注解信息 name、required、defaultValue),无注解则使用parameterName
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
// 支持Optional
MethodParameter nestedParameter = parameter.nestedIfOptional();
// 参数注解中占位符处理
Object resolvedName = resolveStringValue(namedValueInfo.name);
// 参数名解析失败
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
// @RequestParam,通过RequestParamMethodArgumentResolver:从request中parameterMap获取url?之后的参数,基本类型自动处理无需@RequestParam
// @PathVariable,通过PathVariableMethodArgumentResolver:从request中Attribute中获取uriTemplateVariables
// @MatrixVariable,通过MatrixVariableMethodArgumentResolver:从request中Attribute中获取matrixVariables
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
// 如果参数为null则走默认值
if (arg == null) {
// 解析默认值(可能存在占位符)
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
// 如果必须有值且变量不为Optional类型抛出异常ServletRequestBindingException
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
// 如果为boolean类型返回false其他基本类型抛出异常IllegalStateException
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
// 参数值为""且存在默认值则使用默认值
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
// 如果存在@InitBinder,进行数据绑定
if (binderFactory != null) {
// 执行@InitBinder修饰的value为空或value=namedValueInfo.name的方法
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
// 将从request请求获得的arg转换为对应参数类型的值
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
···抛出异常
}
// PathVariableMethodArgumentResolver类使用,将arg存入request的Attribute中
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
更多
- 对于默认的Map入参,使用MapMethodProcessor处理,直接返回ModelAndViewContainer的modelMap。
- 处理器方法支持一些固定参数作为入参。如通过ServletRequestMethodArgumentResolver处理。
- 对于@RequestBody注解等,使用HttpMessageConverter来完成参数转换。
- 一般实体类如User等,使用ModelAttributeMethodProcessor来解析,如果在ModelAttribute中未找到则创建一个空的实体类,通过WebDataBinder将request请求中的参数绑定到实体类对应的字段。