《Spring 高手系列》(@AliasFor)笔记

参考链接1

源码

@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是别名呢? 基本关系如下图所示

在这里插入图片描述

  1. xml跟ContextConfiguration中间的locations互为别名,所以locations=123。
  2. locations和value互为别名,所以value=123。
  3. MyTestConfig里面三个属性都跟ContextConfiguration中的locations互为别名所以groovyScripts =123。
  4. GroovyOrXmlTestConfig中的groovy跟MyTestConfig中的groovyScripts互为别名,groovy = 123.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值