源码
@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;
}
源码注释 Usage Scenarios
Explicit aliases within an annotation:
within a single annotation, @AliasFor can be declared on a pair of attributes to signal that they are interchangeable aliases for each other.
Explicit alias for attribute in meta-annotation:
if the annotation attribute of @AliasFor is set to a different annotation than the one that declares it, the attribute is interpreted as an alias for an attribute in a meta-annotation (i.e., an explicit meta-annotation attribute override).
This enables fine-grained control over exactly which attributes are overridden within an annotation hierarchy.
In fact, with @AliasFor it is even possible to declare an alias for the value attribute of a meta-annotation.
Implicit aliases within an annotation:
if one or more attributes within an annotation are declared as attribute overrides for the same meta-annotation attribute (either directly or transitively), those attributes will be treated as a set of implicit aliases for each other, resulting in behavior analogous to that for explicit aliases within an annotation.
源码注释 Usage Requirements
源码注释示例
Explicit Aliases within an Annotation
Example: Explicit Aliases within an Annotation
In @ContextConfiguration, value and locations are explicit aliases for each other.
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
第一个例子value和locations互为别名
Explicit Alias for Attribute in Meta-annotation
Example: Explicit Alias for Attribute in Meta-annotation
In @XmlTestConfig, xmlFiles is an explicit alias for locations in @ContextConfiguration.
In other words, xmlFiles overrides the locations attribute in @ContextConfiguration.
@ContextConfiguration
public @interface XmlTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles();
}
第二个例子xmlFiles和(Meta-annotation)ContextConfiguration中的locations互为别名
Implicit Aliases within an Annotation 隐含别名
Example: Implicit Aliases within an Annotation
In @MyTestConfig, value, groovyScripts, and xmlFiles are all explicit meta-annotation attribute overrides for the locations attribute in @ContextConfiguration.
These three attributes are therefore also implicit aliases for each other.
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] value() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] groovyScripts() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles() default {};
}
第三个例子,三个属性和(Meta-annotation)ContextConfiguration中的locations是别名,那么他们三个互为别名。
Transitive Implicit Aliases within an Annotation 传递隐含别名
Example: Transitive Implicit Aliases within an Annotation
In @GroovyOrXmlTestConfig, groovy is an explicit override for the groovyScripts attribute in @MyTestConfig;
whereas, xml is an explicit override for the locations attribute in @ContextConfiguration.
Furthermore, groovy and xml are transitive implicit aliases for each other, since they both effectively override the locations attribute in @ContextConfiguration.
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}
第四个例子最终表现xml和groovy互为别名,后面会具体分析。
为什么要使用AliasFor
定义一个注解A1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A1 {
String value() default "a";
}
定义一个注解B1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A1
@interface B1 {
String value() default "b";
}
使用 AnnotatedElementUtils.getMergedAnnotation 来获取注解
@B1("this is b")
public class Demo01 {
public static void main(String[] args) {
//AnnotatedElementUtils是spring提供的一个查找注解的工具类
System.out.println(AnnotatedElementUtils.getMergedAnnotation(Demo01.class, B1.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(Demo01.class, A1.class));
}
}
-----
@com.example.lurenjia.spring.c16.aliasfor.B1(value=this is b)
@com.example.lurenjia.spring.c16.aliasfor.A1(value=a)
如何我们通过B1注解来给A1设置值应该怎么做呢? 在B1注解内部定义一个valueA字段并使用AliasFor注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A1
@interface B1 {
String value() default "b";
@AliasFor(annotation = A1.class, value = "value")
String valueA();
}
这样给B1 valueA字段赋值的同时也就相当于给A1注解的value字段赋值。
@B1(value = "this is b", valueA = "this is a")
---
@com.example.lurenjia.spring.c16.aliasfor.B1(value=this is b, valueA=this is a)
@com.example.lurenjia.spring.c16.aliasfor.A1(value=this is a)
这样就实现了在一个注解中通过一个属性来给另外一个注解赋值。
注解两个字段互为别名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface C1 {
@AliasFor("v2")
String v1() default "";
@AliasFor("v1")
String v2() default "";
}
----
@C1(v1 = " this is v1")
----
@com.example.lurenjia.spring.c16.aliasfor.C1(v1= this is v1, v2= this is v1)
v1和v2互为别名,赋值一个等于赋值两个。
使用@AliasFor不指定value和attribute
定义注解D1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface D1 {
String abc() default "";
}
定义注解E1,使用D1修饰并且 @AliasFor 不指定value和attribute
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@D1()
public @interface E1 {
@AliasFor(annotation = D1.class)
String abc() default "";
}
测试输出
System.out.println(AnnotatedElementUtils.getMergedAnnotation(Demo01.class, D1.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(Demo01.class, E1.class));
----
@com.example.lurenjia.spring.c16.aliasfor.D1(abc=abc..)
@com.example.lurenjia.spring.c16.aliasfor.E1(abc=abc..)
默认情况下会将D1注解中的修饰字段也就是abc作为value和attribute。
多对一别名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@D1()
public @interface F1 {
@AliasFor(annotation = D1.class, value = "abc")
String a() default "";
@AliasFor(annotation = D1.class, value = "abc")
String b() default "";
@AliasFor(annotation = D1.class, value = "abc")
String c() default "";
}
输出
@com.example.lurenjia.spring.c16.aliasfor.F1(a=a, b=a, c=a)
隐含别名
定义:Explicit 和 Implicit ,明显和隐含。简单说能否一眼看出来它们是别名。
代码参照注释示例第四个,测试方法
@GroovyOrXmlTestConfig(xml = {"123"})
public class OfficialClient {
public static void main(String[] args) {
System.out.println(AnnotatedElementUtils.getMergedAnnotation(OfficialClient.class, GroovyOrXmlTestConfig.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(OfficialClient.class, MyTestConfig.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(OfficialClient.class, ContextConfiguration.class));
}
}
输出
@com.example.annotation.aliasForDemo.official.GroovyOrXmlTestConfig(groovy=[123], xml=[123])
@com.example.annotation.aliasForDemo.official.MyTestConfig(groovyScripts=[123], value=[123], xmlFiles=[123])
@com.example.annotation.aliasForDemo.official.ContextConfiguration(locations=[123], value=[123])
这里为什么groovy和xml是别名呢? 基本关系如下图所示
- xml跟ContextConfiguration中间的locations互为别名,所以locations=123。
- locations和value互为别名,所以value=123。
- MyTestConfig里面三个属性都跟ContextConfiguration中的locations互为别名所以groovyScripts =123。
- GroovyOrXmlTestConfig中的groovy跟MyTestConfig中的groovyScripts互为别名,groovy = 123.