一、@AliasFor注解概览
@AliasFor
是Spring Framework中的一个注解,从4.2版本开始出现,源码位于spring-core中,用于注解的属性之上,为该属性声明一个别名。
1.1 Spring官方文档说明
查看Spring中的@AliasFor的文档,英文描述如下:
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.
1.2 翻译解释说明
1.2.1 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
意思是注解中的属性可以互相为别名进行使用
1.2.2 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.
简略意思是注解中使用了元注解时,可以对元注解的值进行重写,目的是为了能达到和类继承中override相似的功能
1.2.3 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.
简略意思是注解中使用了元注解时,可以对元注解的值进行重写,并且可用多个不同的别名进行重写(其实就是一和二的结合)
二、@AliasFor源码说明
2.1 源码
package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@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;
}
2.2 说明
2.2.1 annotation属性
声明别名属性的注释类型。默认为注释,这意味着别名属性在与此属性相同的注释中声明。
2.2.2 attribute属性
此属性是其别名的属性的名称。
2.2.3 value属性
用于在未声明注释时代替属性-例如:@AliasFor(“value”)
而不是@AliasFor(attribute=“value”)
。
三、@AliasFor注解的使用场景
-
在注解中一对属性上通过声明@AliasFor,进行属性互换。
-
在注解上声明了另一个注解,对另一个注解的属性进行别名覆盖。
-
在注解中隐示标明属性的别名。
3.1 在注解中一对属性上通过声明@AliasFor,进行属性互换
构成别名对的每个属性都应该用@AliasFor注释,并且属性或值必须引用该对中的另一个属性。由于Spring Framework 5.2.1,从技术上讲,可以只注释别名对中的一个属性;但是,建议在别名对中对这两个属性进行注释,以获得更好的文档以及与Spring Framework早期版本的兼容性。
3.1.1 举例
假设现在有一个注解@MyAnnotationA
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MyAnnotationA {
String a1() default "";
}
用这个注解时我们可以像这样@MyAnnotationA(a1=“xxx”)
,表示a1的属性传入了xxx的值。假设现在我想换一种方式用这个注解,我打算用这样的@MyAnnotationA(a2=“xxx”)
实现同样的效果,这时就可以通过别名的方式实现。我们修改@MyAnnotationA
。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MyAnnotationA {
@AliasFor("a2")
String a1() default "";
@AliasFor("a1")
String a2() default "";
}
3.1.2 使用说明
-
必须以属性别名对的形式出现,即要求有两个属性,且这两个属性的名字分别为对方别名。
-
这两个属性的必须拥有相同的返回值类型。
-
这两个属性必须拥有相同的默认值。
-
@AliasFor中的annotation()不应该被指定值。
3.1.3 Spring源码中的用法
1、Spring中的@Bean注解
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
2、Spring中的@Scope注解
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
3.2 在注解上声明了另一个注解,对另一个注解的属性进行别名覆盖
3.2.1 举例
再创建一个@MyAnnotationB
注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@MyAnnotationA
public @interface MyAnnotationB {
@AliasFor(annotation = MyAnnotationA.class,value = "a2")
String value() default "";
}
这时@MyAnnotationB(“vvv”)
就和@MyAnnotationA(a2=“vvv”)
等价。这里可以理解成,注解MyAnnotationB的value属性重写了注解MyAnnotationA的a2属性,但重新的属性的返回类型必须相同。
3.2.2 使用说明
-
在需要overrides的注解的属性上使用:@AliasFor(attribute="元注解的属性",annotation="元注解")。
-
被标记@AliasFor的属性和atttibute所指向的元注解属性必须有相同的返回值类型。
-
@AliasFor中annotation指向的元注解必须作用于正在定义的注解上。
3.2.3 Spring源码中的用法
1、Spring中的@Configuration注解
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
可以看出对于value这个属性来说,@Configuration注解中的值会重写@Component的value属性值,这有点像类之间的继承,子类可以重父类的方法。我们也可以将@Configuration注解看成@Component的子注解。
2、Spring中的@SpringBootApplication注解
package org.springframework.boot.autoconfigure;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(
annotation = ComponentScan.class,
attribute = "nameGenerator"
)
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
3.3 在注解中隐示标明属性的别名
3.3.1 对注解定义时,对作用于该注解的元注解的同一属性显示指明别名的多个属性互为别名
如下代码,value、groovyScripts和xmlFiles均为元注解@ContextConfiguration中locations的别名,则这三个属性(value、groovyScripts和xmlFiles)也互为别名。
@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 {};
}
3.3.2 通过别名的传递性隐示标明别名
如下代码,groovy是@MyTestConfig注解中groovyScripts属性的别名,而groovyScripts属性是@ContextConfiguration直接中locations的别名,而xml是@ContextConfiguration直接中locations的别名,所以groovy和xml也互为对方的别名。
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}
网友评论