springboot源码分析:MethodParameter笔记

Scroll Down

1、MethodParameter的API

MethodParameter主要用于表示方法或构造器的参数,加上参数索引和已声明泛型类型的嵌套类型索引。
其中Executable的UML图如下:
image.png

(1)、MethodParameter的字段

// 代表该参数所在的方法,对应的反射类Method
private final Executable executable;

// 标记参数索引
private final int parameterIndex;

// 反射对应的方法参数类型
@Nullable
private volatile Parameter parameter;

// 嵌套级别
private int nestingLevel;

// 类型索引级别
/** Map from Integer level to Integer type index. */
@Nullable
Map<Integer, Integer> typeIndexesPerLevel;

// 缺省情况下表示该参数所在方法的所在类
/** The containing class. Could also be supplied by overriding {@link #getContainingClass()} */
@Nullable
private volatile Class<?> containingClass;

// 代表参数类型
@Nullable
private volatile Class<?> parameterType;

// 代表该方法参数中的泛型类型
@Nullable
private volatile Type genericParameterType;

// 表示该方法参数被标记的注解类型数组
@Nullable
private volatile Annotation[] parameterAnnotations;

// 方法参数名解析器
@Nullable
private volatile ParameterNameDiscoverer parameterNameDiscoverer;

// 方法参数名称
@Nullable
private volatile String parameterName;

// 嵌套方法参数
@Nullable
private volatile MethodParameter nestedMethodParameter;

(2)、MethodParameter中的构造器

/**
 * Create a new {@code MethodParameter} for the given method, with nesting level 1.
 * @param method the Method to specify a parameter for
 * @param parameterIndex the index of the parameter: -1 for the method
 * return type; 0 for the first method parameter; 1 for the second method
 * parameter, etc.
 */
public MethodParameter(Method method, int parameterIndex) {
	this(method, parameterIndex, 1);
}

/**
 * Create a new {@code MethodParameter} for the given method.
 * @param method the Method to specify a parameter for
 * @param parameterIndex the index of the parameter: -1 for the method
 * return type; 0 for the first method parameter; 1 for the second method
 * parameter, etc.
 * @param nestingLevel the nesting level of the target type
 * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
 * nested List, whereas 2 would indicate the element of the nested List)
 */
public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
	Assert.notNull(method, "Method must not be null");
	this.executable = method;
	this.parameterIndex = validateIndex(method, parameterIndex);
	this.nestingLevel = nestingLevel;
}

/**
 * Create a new MethodParameter for the given constructor, with nesting level 1.
 * @param constructor the Constructor to specify a parameter for
 * @param parameterIndex the index of the parameter
 */
public MethodParameter(Constructor<?> constructor, int parameterIndex) {
	this(constructor, parameterIndex, 1);
}

/**
 * Create a new MethodParameter for the given constructor.
 * @param constructor the Constructor to specify a parameter for
 * @param parameterIndex the index of the parameter
 * @param nestingLevel the nesting level of the target type
 * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
 * nested List, whereas 2 would indicate the element of the nested List)
 */
public MethodParameter(Constructor<?> constructor, int parameterIndex, int nestingLevel) {
	Assert.notNull(constructor, "Constructor must not be null");
	this.executable = constructor;
	this.parameterIndex = validateIndex(constructor, parameterIndex);
	this.nestingLevel = nestingLevel;
}

/**
 * Internal constructor used to create a {@link MethodParameter} with a
 * containing class already set.
 * @param executable the Executable to specify a parameter for
 * @param parameterIndex the index of the parameter
 * @param containingClass the containing class
 * @since 5.2
 */
MethodParameter(Executable executable, int parameterIndex, @Nullable Class<?> containingClass) {
	Assert.notNull(executable, "Executable must not be null");
	this.executable = executable;
	this.parameterIndex = validateIndex(executable, parameterIndex);
	this.nestingLevel = 1;
	this.containingClass = containingClass;
}

	/**
	 * Copy constructor, resulting in an independent MethodParameter object
	 * based on the same metadata and cache state that the original object was in.
	 * @param original the original MethodParameter object to copy from
	 */
	public MethodParameter(MethodParameter original) {
		Assert.notNull(original, "Original must not be null");
		this.executable = original.executable;
		this.parameterIndex = original.parameterIndex;
		this.parameter = original.parameter;
		this.nestingLevel = original.nestingLevel;
		this.typeIndexesPerLevel = original.typeIndexesPerLevel;
		this.containingClass = original.containingClass;
		this.parameterType = original.parameterType;
		this.genericParameterType = original.genericParameterType;
		this.parameterAnnotations = original.parameterAnnotations;
		this.parameterNameDiscoverer = original.parameterNameDiscoverer;
		this.parameterName = original.parameterName;
	}

构造器方法中主要有两种方式构造一种是通过提供Method,另一种是提供Constructor的方式。
主要说明下这个类的一些方法:

(3)、MethodParameter中的方法

getMethod:

/**
 * Return the wrapped Method, if any.
 * <p>Note: Either Method or Constructor is available.
 * @return the Method, or {@code null} if none
 */
@Nullable
public Method getMethod() {
	// 判断executable对象是否为Method类型。
	return (this.executable instanceof Method ? (Method) this.executable : null);
}

getConstructor:

/**
 * Return the wrapped Constructor, if any.
 * <p>Note: Either Method or Constructor is available.
 * @return the Constructor, or {@code null} if none
 */
@Nullable
public Constructor<?> getConstructor() {
	// 判断executable对象的类型是否为构造器类型。
	return (this.executable instanceof Constructor ? (Constructor<?>) this.executable : null);
}

getDeclaringClass:

/**
 * Return the class that declares the underlying Method or Constructor.
 */
public Class<?> getDeclaringClass() {
	// 获取executable所在的类的类型。
	return this.executable.getDeclaringClass();
}

getAnnotatedElement:

/**
 * Return the wrapped annotated element.
 * <p>Note: This method exposes the annotations declared on the method/constructor
 * itself (i.e. at the method/constructor level, not at the parameter level).
 * @return the Method or Constructor as AnnotatedElement
 */
public AnnotatedElement getAnnotatedElement() {
	return this.executable;
}

这个接口(AnnotatedElement)的对象代表了在当前JVM中的一个“被注解元素”(可以是Class,Method,Field,Constructor,Package等)。
在Java语言中,所有实现了这个接口的“元素”都是可以“被注解的元素”。使用这个接口中声明的方法可以读取(通过Java的反射机制)“被注解元素”的注解。这个接口中的所有方法返回的注解都是不可变的、并且都是可序列化的。这个接口中所有方法返回的数组可以被调用者修改,而不会影响其返回给其他调用者的数组。
子接口:
AnnotatedArrayType (被注解的数组类型)
AnnotatedParameterizedType (被注解的参数化类型)
AnnotatedType (被注解的类型)
AnnotatedTypeVariable (被注解的类型变量)
AnnotatedWildcardType (被注解的通配类型)
GenericDeclaration (通用声明,用于表示声明型元素,如:类、方法、构造器等)
TypeVariable (类型变量)
实现类:
AccessibleObject(可访问对象,如:方法、构造器、属性等)
Class(类,就是你用Java语言编程时每天都要写的那个东西)
Constructor(构造器,类的构造方法的类型)
Executable(可执行的,如构造器和方法)
Field(属性,类中属性的类型)
Method(方法,类中方法的类型)
Package(包,你每天都在声明的包的类型)
Parameter(参数,主要指方法或函数的参数,其实是这些参数的类型)
getAnnotationsByType(Class)和getDeclaredAnnotationsByType(Class)方法在一个元素上支持多个相同类型的注释。

getParameter:

/**
 * Return the {@link Parameter} descriptor for method/constructor parameter.
 * @since 5.0
 */
public Parameter getParameter() {
	if (this.parameterIndex < 0) {
		throw new IllegalStateException("Cannot retrieve Parameter descriptor for method return type");
	}
	// 获取方法中对应索引的参数。
	Parameter parameter = this.parameter;
	if (parameter == null) {
		parameter = getExecutable().getParameters()[this.parameterIndex];
		this.parameter = parameter;
	}
	return parameter;
}

nested方法:
实质上是对MethodParameter的clone,至于为什么需要nested,尚且不知。代码如下:

/**
 * Return a variant of this {@code MethodParameter} which points to the
 * same parameter but one nesting level deeper.
 * @since 4.3
 */
public MethodParameter nested() {
	return nested(null);
}

/**
 * Return a variant of this {@code MethodParameter} which points to the
 * same parameter but one nesting level deeper.
 * @param typeIndex the type index for the new nesting level
 * @since 5.2
 */
public MethodParameter nested(@Nullable Integer typeIndex) {
	MethodParameter nestedParam = this.nestedMethodParameter;
	if (nestedParam != null && typeIndex == null) {
		return nestedParam;
	}
	nestedParam = nested(this.nestingLevel + 1, typeIndex);
	if (typeIndex == null) {
		this.nestedMethodParameter = nestedParam;
	}
	return nestedParam;
}

private MethodParameter nested(int nestingLevel, @Nullable Integer typeIndex) {
	// clone下。
	MethodParameter copy = clone();
	// 将嵌套级别更新下。
	copy.nestingLevel = nestingLevel;
	if (this.typeIndexesPerLevel != null) {
		copy.typeIndexesPerLevel = new HashMap<>(this.typeIndexesPerLevel);
	}
	if (typeIndex != null) {
		copy.getTypeIndexesPerLevel().put(copy.nestingLevel, typeIndex);
	}
	// parameterType和genericParameterType都需要重新计算。
	copy.parameterType = null;
	copy.genericParameterType = null;
	return copy;
}

withContainingClass方法:

/**
 * Return a variant of this {@code MethodParameter} which refers to the
 * given containing class.
 * @param containingClass a specific containing class (potentially a
 * subclass of the declaring class, e.g. substituting a type variable)
 * @since 5.2
 * @see #getParameterType()
 */
public MethodParameter withContainingClass(@Nullable Class<?> containingClass) {
	MethodParameter result = clone();
	// 设置方法参数所在的类的类型。
	result.containingClass = containingClass;
	result.parameterType = null;
	return result;
}

getParameterType方法:获取方法参数的类型。

/**
 * Return the type of the method/constructor parameter.
 * @return the parameter type (never {@code null})
 */
public Class<?> getParameterType() {
	Class<?> paramType = this.parameterType;
	if (paramType != null) {
		return paramType;
	}
	if (getContainingClass() != getDeclaringClass()) {
		paramType = ResolvableType.forMethodParameter(this, null, 1).resolve();
	}
	// 如果index的值为-1那么就返回返回值类型,否则就使用反射来获取方法index的参数类型
	if (paramType == null) {
		paramType = computeParameterType();
	}
	this.parameterType = paramType;
	return paramType;
}

getGenericParameterType方法:

/**
 * Return the generic type of the method/constructor parameter.
 * @return the parameter type (never {@code null})
 * @since 3.0
 */
public Type getGenericParameterType() {
	Type paramType = this.genericParameterType;
	if (paramType == null) {
		// 如果是返回值类型
		if (this.parameterIndex < 0) {
			Method method = getMethod();
			paramType = (method != null ?
						(KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) ?
						KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class);
		}
		else {
			// 获取方法中的所有泛型类型。
			Type[] genericParameterTypes = this.executable.getGenericParameterTypes();
			int index = this.parameterIndex;
			if (this.executable instanceof Constructor &&
						ClassUtils.isInnerClass(this.executable.getDeclaringClass()) &&
						genericParameterTypes.length == this.executable.getParameterCount() - 1) {
				// Bug in javac: type array excludes enclosing instance parameter
				// for inner classes with at least one generic constructor parameter,
				// so access it with the actual parameter index lowered by 1
				index = this.parameterIndex - 1;
			}
			paramType = (index >= 0 && index < genericParameterTypes.length ?
						genericParameterTypes[index] : computeParameterType());
		}
		this.genericParameterType = paramType;
	}
	return paramType;
}

getParameterAnnotations方法:

/**
 * Return the annotations associated with the specific method/constructor parameter.
 */
public Annotation[] getParameterAnnotations() {
	Annotation[] paramAnns = this.parameterAnnotations;
	if (paramAnns == null) {
		// 通过反射获取参数的所有注解类型。
		Annotation[][] annotationArray = this.executable.getParameterAnnotations();
		int index = this.parameterIndex;
		if (this.executable instanceof Constructor &&
					ClassUtils.isInnerClass(this.executable.getDeclaringClass()) &&
					annotationArray.length == this.executable.getParameterCount() - 1) {
			// Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
			// for inner classes, so access it with the actual parameter index lowered by 1
			index = this.parameterIndex - 1;
		}
		paramAnns = (index >= 0 && index < annotationArray.length ?
					adaptAnnotationArray(annotationArray[index]) : EMPTY_ANNOTATION_ARRAY);
		this.parameterAnnotations = paramAnns;
	}
	return paramAnns;
}