spring-core:理解@AliasFor注解的作用

@AliasFor是spring注解体系中一个非常重要且基础的注解。顾名思义,它的基本作用就是为注解字段定义一个别名。

基本作用:字段别名

	@Test
	public void test3AliasFor() {
		try {
			{
				CasbanScan casbanScan = AnnotationUtils.findAnnotation(UserSummy.class, CasbanScan.class);
				System.out.println(casbanScan);
			}
		} catch (Throwable e) {
			e.printStackTrace();
			fail();
		}
	}
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
	public @interface CasbanScan {
		@AliasFor("basePackages")
		String[] value() default {};
		@AliasFor("value")
		String[] basePackages() default {};
	}

	@CasbanScan("hello")
	public static class UserSummy{
	}
	public static class VipSummy extends UserSummy{
	}

输出

@CasbanScan(basePackages=[hello], value=[hello])

上面的输出可以看到虽然UserSummy类上的@CasbanScan注解只定义了value字段但通过AnnotationUtils.findAnnotation方法获取到的CasbanScan实例basePackages字段也是有与value字段相同的值,这就是@AliasFor注解的基本作用。

更多:注解继承

除了为注解字段定义别名之外,@AliasFor注解更重要的作用是为注解增加了类似Java普通类的继承功能,如下是@AliasFor的定义源码:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {

	/**
	 * Alias for {@link #attribute}.
	 * <p>Intended to be used instead of {@link #attribute} when {@link #annotation}
	 * is not declared &mdash; for example: {@code @AliasFor("value")} instead of
	 * {@code @AliasFor(attribute = "value")}.
	 */
	@AliasFor("attribute")
	String value() default "";

	/**
	 * The name of the attribute that <em>this</em> attribute is an alias for.
	 * @see #value
	 */
	@AliasFor("value")
	String attribute() default "";

	/**
	 * The type of annotation in which the aliased {@link #attribute} is declared.
	 * <p>Defaults to {@link Annotation}, implying that the aliased attribute is
	 * declared in the same annotation as <em>this</em> attribute.
	 */
	Class<? extends Annotation> annotation() default Annotation.class;

}

上面源码可以看到@AliasFor不仅有value字段还有annotation字段,这个字段的字面作用是声明别名属性的所属的注解类型。
怎么理解呢?
我们知道注解(Annotation)类虽然也是一个接口(@interface),但它与Java的标准接口(interface)是不太一样的,它没有继承能力,
如下普通的Java interface类可以从另一个接口类继承(extends),但@interface不行

public interface Request{}
public interface WebRequest extends Request{}

这在一定程序上限制了注解的应用场景。

spring-core的注解体系通过@AliasFor注解为注解设计提供了继承能力。这个继承能力就体现在了@AliasForannotation字段。

如果不定义annotation字段
@AliasForvalueattribute字段用于指定@AliasFor所在字段为同当前注解类内的字段别名。如下例子:value上定义的@AliasFor("basePackages")即指定valuebasePackages字段的别名,反之亦然。

	public @interface CasbanScan {
		@AliasFor("basePackages")
		String[] value() default {};
		@AliasFor("value")
		String[] basePackages() default {};
	}

如果定义了annotation字段
annotation字段可以理解为指定当前字段为定义在当前注解上的注解类指定字段的别名。

如下示例:
@RequestComponent注解上定义了@ScanConfig注解,@RequestComponent注解的subClassFirstly字段上定义了@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")
即定义该字段为@ScanConfigsubClassFirstly的别名

@Retention(RetentionPolicy.RUNTIME)
public @interface ScanConfig {
	String subClassFirstly() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE})
@ScanConfig
public @interface RequestComponent {
	@AliasFor("associated")
	String value() default "";
	@AliasFor("value")
	String associated() default "";
	@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")
	String subClassFirstly() default "";
}

我们可以再定义一个注解@WebComponent也使定义一个firstly字段使用同样的@AliasFor注解,注意这个字段firstly字段与@RequestComponentsubClassFirstly并不同名

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@ScanConfig
public @interface WebComponent {
	String value() default "";
	@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")
	String firstly() default "";
}

展现继承能力

如下示例,调用AnnotatedElementUtils.findMergedAnnotation方法获取类上定义的@ScanConfig

	@Test
	public void test4AliasFor() {
		try {
			{
				ScanConfig scanConfig= AnnotatedElementUtils.findMergedAnnotation(UseRequestComponent.class, ScanConfig.class);
				System.out.printf("ScanConfig:%s in %s\n",
						UseRequestComponent.class.getSimpleName(), 
						AnnotationUtils.getAnnotationAttributes(scanConfig));
				assertEquals("hello", scanConfig.subClassFirstly());
			}
			{
				ScanConfig scanConfig = AnnotatedElementUtils.findMergedAnnotation(UseWebComponent.class, ScanConfig.class);
				System.out.printf("ScanConfig:%s in %s\n",
						UseWebComponent.class.getSimpleName(), 
						AnnotationUtils.getAnnotationAttributes(scanConfig));
				assertEquals("world", scanConfig.subClassFirstly());
			}
		} catch (Throwable e) {
			e.printStackTrace();
			fail();
		}
	}
	@RequestComponent(subClassFirstly="hello")
	public static class UseRequestComponent{
		
	}
	@WebComponent(firstly = "world")
	public static class UseWebComponent{
		
	}

输出

ScanConfig:UseRequestComponent in {subClassFirstly=hello}
ScanConfig:UseWebComponent in {subClassFirstly=world}

如上示例,我们可以从定义了注解@RequestComponent(subClassFirstly="hello")UseRequestComponent类直接获取@ScanConfig注解值
也可以从定义了注解@WebComponent(firstly = "world")UseWebComponent类直接获取@ScanConfig注解值
虽然@RequestComponent@WebComponent是两个不同的注解类,但因为它们都有@ScanConfig注解。所以AnnotatedElementUtils.findMergedAnnotation方法可以从定义了这两个注解的类上读取它们共同定义的@ScanConfig注解,
从这点来看是不是可以视为@RequestComponent@WebComponent都继承了将@ScanConfig注解呢?

所以@AliasFor注解可以为不同的注解提供共同的字段,类似于父类字段。有了这个能力,基于spring-core注解框架设计自己的注解体系就提供了很大的灵活性和便利性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值