SpringMVC-请求参数注入-对象类型参数注入源码探讨

接着上一篇请求参数解析,本篇分析讲请求参数解析为对象属性的源码。
demo基于springboot
与上一篇稍微不同,这里的spring版本为5.1.5。

controller

@RestController
@RequestMapping("/index")
public class TestController {

    @GetMapping("/test")
    public String test(SysUserDto sysUser) {
        System.out.println(sysUser.toString());
        return "ok";
    }

}

接收参数类型为SysUserDto

@Data
public class SysUserDto {
    private Integer id;

    private String name;

    private Integer age;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;

    private SysUserDto userDto;

}

普通类型对象的参数解析器类是ServletModelAttributeMethodProcessor,该类在处理器适配器RequestMappingHandlerAdapter初始化的方法中注册。
先从该类的父类ModelAttributeMethodProcessor#resolveArgument方法开始

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
	Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

	String name = ModelFactory.getNameForParameter(parameter);
	ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
	if (ann != null) {
		mavContainer.setBinding(name, ann.binding());
	}

	Object attribute = null;
	BindingResult bindingResult = null;

	if (mavContainer.containsAttribute(name)) {
		attribute = mavContainer.getModel().get(name);
	}
	else {
		// Create attribute instance
		try {
			//创建对象参数实例
			attribute = createAttribute(name, parameter, binderFactory, webRequest);
		}
		catch (BindException ex) {
			if (isBindExceptionRequired(parameter)) {
				// No BindingResult parameter -> fail with BindException
				throw ex;
			}
			// Otherwise, expose null/empty value and associated BindingResult
			if (parameter.getParameterType() == Optional.class) {
				attribute = Optional.empty();
			}
			bindingResult = ex.getBindingResult();
		}
	}

	if (bindingResult == null) {
		// Bean property binding and validation;
		// skipped in case of binding failure on construction.
		//创建数据绑定器
		WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
		if (binder.getTarget() != null) {
			if (!mavContainer.isBindingDisabled(name)) {
				//绑定请求参数到对象
				bindRequestParameters(binder, webRequest);
			}
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new BindException(binder.getBindingResult());
			}
		}
		// Value type adaptation, also covering java.util.Optional
		if (!parameter.getParameterType().isInstance(attribute)) {
			attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
		}
		bindingResult = binder.getBindingResult();
	}

	// Add resolved attribute and BindingResult at the end of the model
	Map bindingResultModel = bindingResult.getModel();
	mavContainer.removeAttributes(bindingResultModel);
	mavContainer.addAllAttributes(bindingResultModel);

	return attribute;
}

上面代码中对对象类型参数做了几件事,分别是
1.创建对象实例;
2.创建数据绑定器;
3.绑定请求参数到对象;
这里传递进来的binderFactory是ServletRequestDataBinderFactory,其创建的ExtendedServletRequestDataBinder实例。数据绑定器包含了对象类型以及参数名。

接下来看bindRequestParameters方法,ServletModelAttributeMethodProcessor类重写了该方法

protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
	ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
	Assert.state(servletRequest != null, "No ServletRequest");
	ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
	servletBinder.bind(servletRequest);
}

代码很简单,调用bind方法
ServletRequestDataBinder#bind

public void bind(ServletRequest request) {
	//将每个请求参数保存到PropertyValue,并保存为集合
	MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
	//上传文件处理
	MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
	if (multipartRequest != null) {
		bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
	}
	//扩展方法,此处为空
	addBindValues(mpvs, request);
	//绑定实现
	doBind(mpvs);
}

doBind方法最终会调用父类DataBinde的applyPropertyValues方法

protected void doBind(MutablePropertyValues mpvs) {
	checkFieldDefaults(mpvs);
	checkFieldMarkers(mpvs);
	super.doBind(mpvs);
}
protected void doBind(MutablePropertyValues mpvs) {
	checkAllowedFields(mpvs);
	checkRequiredFields(mpvs);
	applyPropertyValues(mpvs);
}
protected void applyPropertyValues(MutablePropertyValues mpvs) {
	try {
		// Bind request parameters onto target object.
		getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
	}
	catch (PropertyBatchUpdateException ex) {
		// Use bind error processor to create FieldErrors.
		for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
			getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
		}
	}
}

再看看getPropertyAccessor方法,通过名字可以知道,获取属性访问器,通过其setPropertyValues方法设置bean的属性。
getPropertyAccessor

protected ConfigurablePropertyAccessor getPropertyAccessor() {
	return getInternalBindingResult().getPropertyAccessor();
}
protected AbstractPropertyBindingResult getInternalBindingResult() {
	if (this.bindingResult == null) {
		//创建BeanPropertyBindingResult实例
		initBeanPropertyAccess();
	}
	return this.bindingResult;
}

BeanPropertyBindingResult#getPropertyAccessor

public final ConfigurablePropertyAccessor getPropertyAccessor() {
	if (this.beanWrapper == null) {
		//创建BeanWrapperImpl,其实现了PropertyAccessor接口
		this.beanWrapper = createBeanWrapper();
		this.beanWrapper.setExtractOldValueForEditor(true);
		this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
		this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
	}
	return this.beanWrapper;
}

getPropertyAccessor方法先创建BeanPropertyBindingResult实例,然后调用其getPropertyAccessor方法,其创建BeanWrapperImpl实例,其实现了PropertyAccessor接口。
接着先调用AbstractPropertyAccessor类的setPropertyValues方法,最后通过循环调用AbstractNestablePropertyAccessor类的setPropertyValue方法

public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
		throws BeansException {

	List propertyAccessExceptions = null;
	List propertyValues = (pvs instanceof MutablePropertyValues ?
			((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
	for (PropertyValue pv : propertyValues) {
		try {
			// This method may throw any BeansException, which won't be caught
			// here, if there is a critical failure such as no matching field.
			// We can attempt to deal only with less serious exceptions.
			setPropertyValue(pv);
		}
		省略无关代码...
	}

	// If we encountered individual exceptions, throw the composite exception.
	if (propertyAccessExceptions != null) {
		PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
		throw new PropertyBatchUpdateException(paeArray);
	}
}

AbstractNestablePropertyAccessor#setPropertyValue

public void setPropertyValue(PropertyValue pv) throws BeansException {
	PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
	if (tokens == null) {
		String propertyName = pv.getName();
		AbstractNestablePropertyAccessor nestedPa;
		try {
			//获取属性的bean,如果是嵌套类,则返回嵌套类的bean
			nestedPa = getPropertyAccessorForPropertyPath(propertyName);
		}
		catch (NotReadablePropertyException ex) {
			throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
					"Nested property in path '" + propertyName + "' does not exist", ex);
		}
		tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
		if (nestedPa == this) {
			pv.getOriginalPropertyValue().resolvedTokens = tokens;
		}
		//设置参数值
		nestedPa.setPropertyValue(tokens, pv);
	}
	else {
		setPropertyValue(tokens, pv);
	}
}

getPropertyAccessorForPropertyPath方法比较重要,其通过递归调用处理了嵌套类的情况。

protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
	int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
	// Handle nested properties recursively.
	if (pos > -1) {
		String nestedProperty = propertyPath.substring(0, pos);
		String nestedPath = propertyPath.substring(pos + 1);
		//生成嵌套类的bean对象
		AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);
		//递归调用嵌套类
		return nestedPa.getPropertyAccessorForPropertyPath(nestedPath);
	}
	else {
		return this;
	}
}

getNestedPropertyAccessor

private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
	if (this.nestedPropertyAccessors == null) {
		this.nestedPropertyAccessors = new HashMap<>();
	}
	// Get value of bean property.
	PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
	String canonicalName = tokens.canonicalName;
	Object value = getPropertyValue(tokens);
	if (value == null || (value instanceof Optional && !((Optional) value).isPresent())) {
		if (isAutoGrowNestedPaths()) {
			//为请求参数对象的属性设置默认值
			value = setDefaultValue(tokens);
		}
		else {
			throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);
		}
	}

	// Lookup cached sub-PropertyAccessor, create new one if not found.
	AbstractNestablePropertyAccessor nestedPa = this.nestedPropertyAccessors.get(canonicalName);
	if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
		}
		nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
		// Inherit all type-specific PropertyEditors.
		copyDefaultEditorsTo(nestedPa);
		copyCustomEditorsTo(nestedPa, canonicalName);
		this.nestedPropertyAccessors.put(canonicalName, nestedPa);
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("Using cached nested property accessor for property '" + canonicalName + "'");
		}
	}
	return nestedPa;
}

setDefaultValue

private Object setDefaultValue(PropertyTokenHolder tokens) {
	PropertyValue pv = createDefaultPropertyValue(tokens);
	setPropertyValue(tokens, pv);
	Object defaultValue = getPropertyValue(tokens);
	Assert.state(defaultValue != null, "Default value must not be null");
	return defaultValue;
}
private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) {
	TypeDescriptor desc = getPropertyTypeDescriptor(tokens.canonicalName);
	if (desc == null) {
		throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName,
				"Could not determine property type for auto-growing a default value");
	}
	Object defaultValue = newValue(desc.getType(), desc, tokens.canonicalName);
	return new PropertyValue(tokens.canonicalName, defaultValue);
}

newValue方法为不同类型的属性创建实例

private Object newValue(Class type, @Nullable TypeDescriptor desc, String name) {
	try {
		if (type.isArray()) {
			Class componentType = type.getComponentType();
			// TODO - only handles 2-dimensional arrays
			if (componentType.isArray()) {
				Object array = Array.newInstance(componentType, 1);
				Array.set(array, 0, Array.newInstance(componentType.getComponentType(), 0));
				return array;
			}
			else {
				return Array.newInstance(componentType, 0);
			}
		}
		else if (Collection.class.isAssignableFrom(type)) {
			TypeDescriptor elementDesc = (desc != null ? desc.getElementTypeDescriptor() : null);
			return CollectionFactory.createCollection(type, (elementDesc != null ? elementDesc.getType() : null), 16);
		}
		else if (Map.class.isAssignableFrom(type)) {
			TypeDescriptor keyDesc = (desc != null ? desc.getMapKeyTypeDescriptor() : null);
			return CollectionFactory.createMap(type, (keyDesc != null ? keyDesc.getType() : null), 16);
		}
		else {
			//普通对象,调用反射创建实例
			Constructor ctor = type.getDeclaredConstructor();
			if (Modifier.isPrivate(ctor.getModifiers())) {
				throw new IllegalAccessException("Auto-growing not allowed with private constructor: " + ctor);
			}
			return BeanUtils.instantiateClass(ctor);
		}
	}
	catch (Throwable ex) {
		throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
				"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
	}
}

最后第二步,调用AbstractNestablePropertyAccessor类的setPropertyValue方法

protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
	if (tokens.keys != null) {
		processKeyedProperty(tokens, pv);
	}
	else {
		//普通属性处理
		processLocalProperty(tokens, pv);
	}
}

processLocalProperty

private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
	PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
	if (ph == null || !ph.isWritable()) {
		if (pv.isOptional()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Ignoring optional value for property '" + tokens.actualName +
						"' - property not found on bean class [" + getRootClass().getName() + "]");
			}
			return;
		}
		else {
			throw createNotWritablePropertyException(tokens.canonicalName);
		}
	}

	Object oldValue = null;
	try {
		Object originalValue = pv.getValue();
		Object valueToApply = originalValue;
		if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
			if (pv.isConverted()) {
				valueToApply = pv.getConvertedValue();
			}
			else {
				if (isExtractOldValueForEditor() && ph.isReadable()) {
					try {
						oldValue = ph.getValue();
					}
					catch (Exception ex) {
						if (ex instanceof PrivilegedActionException) {
							ex = ((PrivilegedActionException) ex).getException();
						}
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read previous value of property '" +
									this.nestedPath + tokens.canonicalName + "'", ex);
						}
					}
				}
				valueToApply = convertForProperty(
						tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
			}
			pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
		}
		//完成属性注入
		ph.setValue(valueToApply);
	}
	catch (TypeMismatchException ex) {
		throw ex;
	}
	catch (InvocationTargetException ex) {
		PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		if (ex.getTargetException() instanceof ClassCastException) {
			throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
		}
		else {
			Throwable cause = ex.getTargetException();
			if (cause instanceof UndeclaredThrowableException) {
				// May happen e.g. with Groovy-generated methods
				cause = cause.getCause();
			}
			throw new MethodInvocationException(propertyChangeEvent, cause);
		}
	}
	catch (Exception ex) {
		PropertyChangeEvent pce = new PropertyChangeEvent(
				getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
		throw new MethodInvocationException(pce, ex);
	}
}

通过反射注入属性,BeanWrapperImpl#setValue

public void setValue(final @Nullable Object value) throws Exception {
		final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
				((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
				this.pd.getWriteMethod());
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction) () -> {
				ReflectionUtils.makeAccessible(writeMethod);
				return null;
			});
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction) () ->
						writeMethod.invoke(getWrappedInstance(), value), acc);
			}
			catch (PrivilegedActionException ex) {
				throw ex.getException();
			}
		}
		else {
			ReflectionUtils.makeAccessible(writeMethod);
			writeMethod.invoke(getWrappedInstance(), value);
		}
	}
 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(Spring)