Spring源码深度解析(郝佳)-学习-源码解析-@AliasFor标签

在研究Spring源码关于注解解析时,发现有源码中有很大的篇幅在处理关于AliasFor标签。我在网上找了一下,发现Spring中的@AliasFor标签 这篇博客对@AliasFor的使用己经介绍得很详细了,只是对源码的具体处理方面,我觉得,如果不是研究过源码的同学,可能还是觉得镜花水月,因此,今天,对其中的一个具体的示例做一下分析,希望对大家有用,先上示例吧

AliasFor.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {
	@AliasFor("attribute")
	String value() default "";
	
	@AliasFor("value")
	String attribute() default "";
	
	Class<? extends Annotation> annotation() default Annotation.class;

}

我们简单来看看@AliasFor标签的使用原理;
可以看到,@AliasFor标签自己就使用了自己,为value属性添加了attribute属性作为别名;

ParentMyAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ParentMyAnnotation {
    @AliasFor(value = "bbbb")
    String aaaa() default "";

    @AliasFor(value = "aaaa")
    String bbbb() default "";
}

MyAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@ParentMyAnnotation
public @interface MyAnnotation {

    @AliasFor(attribute = "aaaa", annotation = ParentMyAnnotation.class)
    String xxxx() default "";

    @AliasFor(attribute = "bbbb", annotation = ParentMyAnnotation.class)   //缺省指明继承的父注解的中的属性名称,则默认继承父注解中同名的属性名
    String yyyy() default "";

    @AliasFor(attribute = "bbbb", annotation = ParentMyAnnotation.class)   //缺省指明继承的父注解的中的属性名称,则默认继承父注解中同名的属性名
    String zzzz() default "";

}

SubMyAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@MyAnnotation
public @interface SubMyAnnotation {

    @AliasFor(annotation = ParentMyAnnotation.class,attribute = "aaaa")
    String iiii() default "";

    @AliasFor(annotation = MyAnnotation.class, attribute = "zzzz")
    String jjjj() default "";

}

GrandsonMyAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@SubMyAnnotation
public @interface GrandsonMyAnnotation {

    @AliasFor(annotation = MyAnnotation.class,attribute = "zzzz")
    String mmmm() default "";

    @AliasFor(annotation = SubMyAnnotation.class, attribute = "iiii")
    String nnnn() default "";


}

定义三个注解类 ParentMyAnnotation,MyAnnotation,SubMyAnnotation,他们之间的关系是SubMyAnnotation继承MyAnnotation,MyAnnotation继承ParentMyAnnotation,GrandsonMyAnnotation 继承SubMyAnnotation。

MyAliasClass.java

@SubMyAnnotation(iiii = "11111111111")
public class MyAliasClass {
}

今天我们要测试的是,别名的传递,因为这个也是解析最为复杂的形式
@AliasFor注解是允许别名之间的传递的,简单理解,如果A是B的别名,并且B是C的别名,那么A是C的别名;
测试:

@Test
public void test2() {
    MyAliasClass aliasTest  = new MyAliasClass();
    MyAnnotation myAnnotation = AnnotationUtils.getAnnotation(aliasTest.getClass(), MyAnnotation.class);
    System.out.println("xxxx:" + myAnnotation.xxxx() + ";yyyy:" + myAnnotation.yyyy());
}

结果:
在这里插入图片描述

为什么SubMyAnnotation中的属性iiii,和jjjj相等呢?那我们来直接进入源码分析吧

AnnotationUtils.java

public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
	try {
		//获取当前类的注解,这里主要是获取到interface com.spring_1_100.test_61_70.test64_1.SubMyAnnotation 的注解
		A annotation = annotatedElement.getAnnotation(annotationType);
		if (annotation == null) {
			for (Annotation metaAnn : annotatedElement.getAnnotations()) {
				annotation = metaAnn.annotationType().getAnnotation(annotationType);
				if (annotation != null) {
					break;
				}
			}
		}
		//获取合成注解,可能返回的是一个代理类
		return synthesizeAnnotation(annotation, annotatedElement);
	}
	catch (Exception ex) {
		handleIntrospectionFailure(annotatedElement, ex);
	}
	return null;
}


public static <A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement) {
	//注解为空,直接返回
	if (annotation == null) {
		return null;
	}
	//如果是合成注解,直接返回
	if (annotation instanceof SynthesizedAnnotation) {
		return annotation;
	}
	//获取注解的类型
	Class<? extends Annotation> annotationType = annotation.annotationType();
	//非合成注解类型,直接返回,【重点分析,注解类型到底是不是合成注解】
	if (!isSynthesizable(annotationType)) {
		return annotation;
	}
	//如果是合成注解类型,创建合成注解代理类
	DefaultAnnotationAttributeExtractor attributeExtractor =
			new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
	InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
	A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(),
			new Class<?>[] {(Class<A>) annotationType, SynthesizedAnnotation.class}, handler);

	return synthesizedAnnotation;
}


//从缓存中获取的情况,我们不考虑,只分析没有缓存的情况
private static boolean isSynthesizable(Class<? extends Annotation> annotationType) {
	Boolean synthesizable = synthesizableCache.get(annotationType);
	if (synthesizable != null) {
		return synthesizable.booleanValue();
	}

	synthesizable = Boolean.FALSE;
	for (Method attribute : getAttributeMethods(annotationType)) {
		//获取当前注解的别名,如果别名不为空,则表示是可合并属性
		if (!getAttributeAliasNames(attribute).isEmpty()) {
			synthesizable = Boolean.TRUE;
			break;
		}
		Class<?> returnType = attribute.getReturnType();
		if (Annotation[].class.isAssignableFrom(returnType)) {
			Class<? extends Annotation> nestedAnnotationType =
					(Class<? extends Annotation>) returnType.getComponentType();
			if (isSynthesizable(nestedAnnotationType)) {
				synthesizable = Boolean.TRUE;
				break;
			}
		}
		else if (Annotation.class.isAssignableFrom(returnType)) {
			Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType;
			if (isSynthesizable(nestedAnnotationType)) {
				synthesizable = Boolean.TRUE;
				break;
			}
		}
	}

	synthesizableCache.put(annotationType, synthesizable);
	return synthesizable.booleanValue();
}


static List<Method> getAttributeMethods(Class<? extends Annotation> annotationType) {
	List<Method> methods = attributeMethodsCache.get(annotationType);
	if (methods != null) {
		return methods;
	}

	methods = new ArrayList<Method>();
	//遍历注解所有的属性方法,将注解属性方法参数个数为0,并且返回值不为void类型的保存到methods中,并返回
	for (Method method : annotationType.getDeclaredMethods()) {
		if (isAttributeMethod(method)) {
			ReflectionUtils.makeAccessible(method);
			methods.add(method);
		}
	}

	attributeMethodsCache.put(annotationType, methods);
	return methods;
}


static List<String> getAttributeAliasNames(Method attribute) {
	Assert.notNull(attribute, "attribute must not be null");
	AliasDescriptor descriptor = AliasDescriptor.from(attribute);
	return (descriptor == null ? Collections.<String> emptyList() : descriptor.getAttributeAliasNames());
}

AliasDescriptor.java

public static AliasDescriptor from(Method attribute) {
	AliasDescriptor descriptor = aliasDescriptorCache.get(attribute);
	if (descriptor != null) {
		return descriptor;
	}
	//注解的属性方法中是否配置了@AliasFor注解
	AliasFor aliasFor = attribute.getAnnotation(AliasFor.class);
	if (aliasFor == null) {
		return null;
	}
	
	descriptor = new AliasDescriptor(attribute, aliasFor);
	
	descriptor.validate();
	aliasDescriptorCache.put(attribute, descriptor);
	return descriptor;
}

private AliasDescriptor(Method sourceAttribute, AliasFor aliasFor) {
	// 注解类
	Class<?> declaringClass = sourceAttribute.getDeclaringClass();
	Assert.isTrue(declaringClass.isAnnotation(), "sourceAttribute must be from an annotation");
	// 源注解属性
	this.sourceAttribute = sourceAttribute;
	// 注解类
	this.sourceAnnotationType = (Class<? extends Annotation>) declaringClass;
	// 源注解属性名称
	this.sourceAttributeName = this.sourceAttribute.getName();
	//如果注解属性没有配置annotation,则别名注解类型是当前注解类
	//如果如果注解属性配置了annotation,则别名注解类型是配置的注解类型
	this.aliasedAnnotationType = (Annotation.class.equals(aliasFor.annotation()) ?
			this.sourceAnnotationType : aliasFor.annotation());
	//获取注解属性所配置的@aliasFor注解的attribute 属性值 ,或name属性值
	// 而 attribute 和 name 有且只有一个不为空或空串的值,则取出来
	// 比如  attribute = "aaa", name="bbb" 抛出异常
	// 比如  attribute = "", name="" 抛出异常
	// 比如  attribute = "zzzz", name="" 或 attribute = "", name="bbb" ,不会抛出异常,并返回zzzz或bbb
	this.aliasedAttributeName = getAliasedAttributeName(aliasFor, this.sourceAttribute);
	try {
		// 这个不好理解,我们举个例子吧 配置如下 
		// @AliasFor(annotation = MyAnnotation.class, attribute = "zzzz")
    	// String jjjj() default "";
		// sourceAttribute :public abstract java.lang.String com.spring_1_100.test_61_70.test64_1.SubMyAnnotation.jjjj()
		// sourceAnnotationType :interface com.spring_1_100.test_61_70.test64_1.SubMyAnnotation
		// aliasedAnnotationType  :interface com.spring_1_100.test_61_70.test64_1.MyAnnotation
		// 得到 aliasedAttribute :public abstract java.lang.String com.spring_1_100.test_61_70.test64_1.MyAnnotation.zzzz()
		// 假如:@MyAnnotation注解中没有zzzz属性,将抛出下面异常
		this.aliasedAttribute = this.aliasedAnnotationType.getDeclaredMethod(this.aliasedAttributeName);
	}
	catch (NoSuchMethodException ex) {
		String msg = String.format(
				"Attribute [%s] in annotation [%s] is declared as an @AliasFor nonexistent attribute [%s] in annotation [%s].",
				this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName,
				this.aliasedAnnotationType.getName());
		throw new AnnotationConfigurationException(msg, ex);
	}
	//如果注解属性配置了@AliasFor 并且设置了annotation属性,isAliasPair为false,否则为true
	this.isAliasPair = this.sourceAnnotationType.equals(this.aliasedAnnotationType);
}

//进行验证
private void validate() {
	// 如果注解属性的注解@AliasFor配置了annotation,但是annotation 不是当前注解类的父类或者祖先类,抛出异常
	// 如果annotation配置了是当前类的子类,比如在SubMyAnnotation的属性中配置了GrandsonMyAnnotation,
	// 而GrandsonMyAnnotation继承SubMyAnnotation,将抛出异常 
	if (!this.isAliasPair && !isAnnotationMetaPresent(this.sourceAnnotationType, this.aliasedAnnotationType)) {
		String msg = String.format("@AliasFor declaration on attribute [%s] in annotation [%s] declares " +
				"an alias for attribute [%s] in meta-annotation [%s] which is not meta-present.",
				this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName,
				this.aliasedAnnotationType.getName());
		throw new AnnotationConfigurationException(msg);
	}

	if (this.isAliasPair) {
		AliasFor mirrorAliasFor = this.aliasedAttribute.getAnnotation(AliasFor.class);
		if (mirrorAliasFor == null) {
			String msg = String.format(
					"Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s].",
					this.aliasedAttributeName, this.sourceAnnotationType.getName(), this.sourceAttributeName);
			throw new AnnotationConfigurationException(msg);
		}
		// 如果源属性和别名注解属性的值不相等,抛出异常
		String mirrorAliasedAttributeName = getAliasedAttributeName(mirrorAliasFor, this.aliasedAttribute);
		if (!this.sourceAttributeName.equals(mirrorAliasedAttributeName)) {
			String msg = String.format(
					"Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].",
					this.aliasedAttributeName, this.sourceAnnotationType.getName(), this.sourceAttributeName,
					mirrorAliasedAttributeName);
			throw new AnnotationConfigurationException(msg);
		}
	}
	Class<?> returnType = this.sourceAttribute.getReturnType();
	Class<?> aliasedReturnType = this.aliasedAttribute.getReturnType();
	//如果源注解属性和别名注解属性返回值不相等,抛出异常
	if (!returnType.equals(aliasedReturnType)) {
		String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " +
				"and attribute [%s] in annotation [%s] must declare the same return type.",
				this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName,
				this.aliasedAnnotationType.getName());
		throw new AnnotationConfigurationException(msg);
	}

	if (this.isAliasPair) {
		validateDefaultValueConfiguration(this.aliasedAttribute);
	}
}


private void validateDefaultValueConfiguration(Method aliasedAttribute) {
	Assert.notNull(aliasedAttribute, "aliasedAttribute must not be null");
	Object defaultValue = this.sourceAttribute.getDefaultValue();
	Object aliasedDefaultValue = aliasedAttribute.getDefaultValue();
	//如果默认值为空,抛出异常
	if (defaultValue == null || aliasedDefaultValue == null) {
		String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " +
				"and attribute [%s] in annotation [%s] must declare default values.",
				this.sourceAttributeName, this.sourceAnnotationType.getName(), aliasedAttribute.getName(),
				aliasedAttribute.getDeclaringClass().getName());
		throw new AnnotationConfigurationException(msg);
	}
	//如果源注解属性和别名注解属性值默认值不相等,抛出异常
	if (!ObjectUtils.nullSafeEquals(defaultValue, aliasedDefaultValue)) {
		String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " +
				"and attribute [%s] in annotation [%s] must declare the same default value.",
				this.sourceAttributeName, this.sourceAnnotationType.getName(), aliasedAttribute.getName(),
				aliasedAttribute.getDeclaringClass().getName());
		throw new AnnotationConfigurationException(msg);
	}
}

AnnotationUtils.java

public List<String> getAttributeAliasNames() {
	// Explicit alias pair?
	if (this.isAliasPair) {
		return Collections.singletonList(this.aliasedAttributeName);
	}

	// Else: search for implicit aliases
	List<String> aliases = new ArrayList<String>();
	for (AliasDescriptor otherDescriptor : getOtherDescriptors()) {
		if (this.isAliasFor(otherDescriptor)) {
			//验证当前注解及otherDescriptor的默认值是否为空,任意一个为空,抛出异常,且如果不相等,抛出异常
			this.validateAgainst(otherDescriptor);
			//将otherDescriptor注解的别名加入到aliases
			aliases.add(otherDescriptor.sourceAttributeName);
		}
	}
	return aliases;
}


private List<AliasDescriptor> getOtherDescriptors() {
	List<AliasDescriptor> otherDescriptors = new ArrayList<AliasDescriptor>();
	for (Method currentAttribute : getAttributeMethods(this.sourceAnnotationType)) {
		//将非源注解的其他注解转化AliasDescriptor成加入到otherDescriptors中
		if (!this.sourceAttribute.equals(currentAttribute)) {
			AliasDescriptor otherDescriptor = AliasDescriptor.from(currentAttribute);
			if (otherDescriptor != null) {
				otherDescriptors.add(otherDescriptor);
			}
		}
	}
	return otherDescriptors;
}

// 递归当前注解及别名注解与其他注解属性的注解及别名注解,两者看有没有相等的,如果有相等,则返回true
private boolean isAliasFor(AliasDescriptor otherDescriptor) {
	for (AliasDescriptor lhs = this; lhs != null; lhs = lhs.getAttributeOverrideDescriptor()) {
		for (AliasDescriptor rhs = otherDescriptor; rhs != null; rhs = rhs.getAttributeOverrideDescriptor()) {
			if (lhs.aliasedAttribute.equals(rhs.aliasedAttribute)) {
				return true;
			}
		}
	}
	return false;
}

private AliasDescriptor getAttributeOverrideDescriptor() {
	//如果注解属性没有配置annotation
	if (this.isAliasPair) {
		return null;
	}
	//如果配置了annotation,则找当前注解属性的别名属性,转化为AliasDescriptor对象
	return AliasDescriptor.from(this.aliasedAttribute);
}

DefaultAnnotationAttributeExtractor.java

DefaultAnnotationAttributeExtractor(Annotation annotation, AnnotatedElement annotatedElement) {
	super(annotation.annotationType(), annotatedElement, annotation);
}

AbstractAliasAwareAnnotationAttributeExtractor.java

AbstractAliasAwareAnnotationAttributeExtractor(Class<? extends Annotation> annotationType,
		AnnotatedElement annotatedElement, S source) {

	Assert.notNull(annotationType, "annotationType must not be null");
	Assert.notNull(source, "source must not be null");
	this.annotationType = annotationType;
	this.annotatedElement = annotatedElement;
	this.source = source;
	this.attributeAliasMap = AnnotationUtils.getAttributeAliasMap(annotationType);
}

在这里插入图片描述

到这里终于将注解解析完成了,那么是如何获取iiii的值的呢?

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	if (isEqualsMethod(method)) {
		return annotationEquals(args[0]);
	}
	if (isHashCodeMethod(method)) {
		return annotationHashCode();
	}
	if (isToStringMethod(method)) {
		return annotationToString();
	}
	//方法的名称是annotationType,返回值为0
	if (isAnnotationTypeMethod(method)) {
		return annotationType();
	}
	//方法的参数个数为大于0或者方法返回值为void类型
	if (!isAttributeMethod(method)) {
		String msg = String.format("Method [%s] is unsupported for synthesized annotation type [%s]", method,
			annotationType());
		throw new AnnotationConfigurationException(msg);
	}
	return getAttributeValue(method);
}

private Object getAttributeValue(Method attributeMethod) {
	String attributeName = attributeMethod.getName();
	Object value = this.valueCache.get(attributeName);
	if (value == null) {
		// 调用 DefaultAnnotationAttributeExtractor 的属性方法
		value = this.attributeExtractor.getAttributeValue(attributeMethod);
		if (value == null) {
			throw new IllegalStateException(String.format(
				"%s returned null for attribute name [%s] from attribute source [%s]",
				this.attributeExtractor.getClass().getName(), attributeName, this.attributeExtractor.getSource()));
		}

		// Synthesize nested annotations before returning them.
		if (value instanceof Annotation) {
			value = synthesizeAnnotation((Annotation) value, this.attributeExtractor.getAnnotatedElement());
		}
		else if (value instanceof Annotation[]) {
			value = synthesizeAnnotationArray((Annotation[]) value, this.attributeExtractor.getAnnotatedElement());
		}

		this.valueCache.put(attributeName, value);
	}
	// Clone arrays so that users cannot alter the contents of values in our cache.
	if (value.getClass().isArray()) {
		value = cloneArray(value);
	}

	return value;
}

AbstractAliasAwareAnnotationAttributeExtractor.java

public final Object getAttributeValue(Method attributeMethod) {
	//获取当前注解属性名称
	final String attributeName = attributeMethod.getName();
	//通过反射获取属性值
	Object attributeValue = getRawAttributeValue(attributeMethod);
	//获取当前注解的所有别名
	List<String> aliasNames = this.attributeAliasMap.get(attributeName);
	if (aliasNames != null) {
		//获取当前注解默认值
		final Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName);
		for (String aliasName : aliasNames) {
			//获取别名注释用户配置的值,如果用户没有配置,则使用默认值
			Object aliasValue = getRawAttributeValue(aliasName);
			//如果 iiii="1111",jjjj="2222" 而iiii 的默认值为 "" ,抛出异常
			//如果iiii="1111",jjjj="",默认值为"",不会抛出异常
			if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
					!ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
					!ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
				String elementName = (getAnnotatedElement() != null ? getAnnotatedElement().toString() : "unknown element");
				throw new AnnotationConfigurationException(String.format(
						"In annotation [%s] declared on %s and synthesized from [%s], attribute '%s' and its " +
						"alias '%s' are present with values of [%s] and [%s], but only one is permitted.",
						getAnnotationType().getName(), elementName, getSource(), attributeName, aliasName,
						ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue)));
			}
			// 如果iiii="",默认值为"",则使用别名属性值jjjj配置的值作为返回值
			if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
				attributeValue = aliasValue;
			}
		}
	}
	return attributeValue;
}

到这里,我们终于将Spring的注解属性解析讲完了。整个过程比较繁索,下面我们来总结一下

  1. 如果注解属性中没有配置了annotation,那么整个过程比较简单,只要看别名注解属性的默认值,和返回值,是不是相等,如果相等,则可以创建代理注解类,来获取注解属性值。
  2. 如果注解属性中配置了annotation,要看annotation配置类是不是当前注解属性所在类的子孙类,如果不在,则抛出异常。再检测注解属性和别名属性返回值是否相等,不相等,抛出异常。
  3. 获取注解属性的所有别名,如果别名不为空,则是创建代理注解处理器
  4. 通过代理获取注解属性。

Spring的每一个细节都非常的有意思,读者,有意向,还是自己下载代码,研究一下,使我们不仅仅停留在表示肤浅的理解注解。

本文的github地址是https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_61_70/test64_1

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值