@AliasFor是用于为注解属性声明别名的注解,从Spring Framework 4.2开始,核心Spring中的几个注释已更新为使用@AliasFor配置其内部属性别名。
与Java中的任何注释一样,仅仅是@AliasFor本身的存在不会强制执行别名语义。要强制执行别名语义,必须通过AnnotationUtils中的方法加载注解。在幕后,Spring将通过将注释包装在一个动态代理中来合成注解,该代理透明地为使用@AliasFor注解的注解属性强制执行属性别名语义。类似地,当在注解层次结构中使用@AliasFor时,AnnotatedElementUtils支持显式元注解属性重写。通常,您不需要自己手动合成注解,因为当在Spring管理的组件上查找注解时,Spring将透明地为您合成注解。
到了Spring5.2则通过MergedAnnotations加载注解。
注解中的显式别名:
元注释中属性的显式别名:
注释中的隐式别名:
在@ContextConfiguration中,value和locations是彼此的显式别名。
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
在@XmlTestConfig中,xmlFiles是@ContextConfiguration中locations的显式别名。 换句话说,xmlFiles覆盖@ContextConfiguration中的locations属性。
@ContextConfiguration
public @interface XmlTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles();
}
在@MyTestConfig中,value,groovyScripts和xmlFiles都是@ContextConfiguration中locations属性的显式元注解属性替代。 因此,这三个属性也是彼此的隐式别名。
@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 {};
}
在@GroovyOrXmlTestConfig中,groovy是@MyTestConfig中groovyScripts属性的显式替代。 xml是@ContextConfiguration中的locations属性的显式替代。 此外,groovy和xml是彼此的传递式隐式别名,因为它们都有效地覆盖了@ContextConfiguration中的locations属性。
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}
提供对合并注解的集合的访问,这些注释通常从类或方法上获得。每个合并的注解表示一个视图,在该视图中可以从不同的源值“合并”属性值,通常是:
例如,假设@PostMapping注解的定义如下:
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = RequestMethod.POST)
public @interface PostMapping {
@AliasFor(attribute = "path")
String[] value() default {};
@AliasFor(attribute = "value")
String[] path() default {};
}
如果使用@PostMapping("/home")注解方法,则它将包含针对@PostMapping和元注解@RequestMapping的合并注解。 @RequestMapping注解的合并视图将包含以下属性:
Name | Value | Source |
value | "/home" | 在@PostMapping中声明 |
path | "/home" | 显示别名@AliasFor |
可以从任何Java AnnotatedElement获得MergedAnnotations。 它们也可以用于不使用反射的源(例如直接解析字节码的源)。
可以使用不同的搜索策略来查找包含要聚合的注解的相关来源元素。 例如,MergedAnnotations.SearchStrategy.TYPE_HIERARCHY将搜索超类和已实现的接口。
从MergedAnnotations实例,您可以获取单个注解,也可以流式传输所有注解或仅匹配特定类型的注释。 您还可以快速判断是否存在注释。
// 是否存在该(元)注解
mergedAnnotations.isPresent(ExampleAnnotation.class);
// 获取ExampleAnnotation的合并的“值”属性(直接注解或元注解)
mergedAnnotations.get(ExampleAnnotation.class).getString("value");
// 获取所有元注释,但不包括直接注解
mergedAnnotations.stream().filter(MergedAnnotation::isMetaPresent);
// 获取所有ExampleAnnotation声明(包括任何元注释)并打印合并的“value”属性
mergedAnnotations.stream(ExampleAnnotation.class)
.map(mergedAnnotation -> mergedAnnotation.getString("value"))
.forEach(System.out::println);
MergedAnnotations接口提供了一组静态重载方法来实例化一个MergedAnnotations对象:
static MergedAnnotations from(AnnotatedElement element) {
return from(element, SearchStrategy.DIRECT);
}
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy) {
return from(element, searchStrategy, RepeatableContainers.standardRepeatables());
}
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers) {
return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN);
}
//创建一个新的MergedAnnotations实例,该实例包含指定元素的所有注解和元注解,
//并取决于MergedAnnotations.SearchStrategy,相关的继承元素。
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
//调用子类静态方法,返回一个子类的实例对象
return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, annotationFilter);
}
MergedAnnotations内部定义了一个枚举类SearchStrategy,表示查找注解的搜索策略。
AnnotationFilter用于过滤调用指定注解类型的接口,内部定义了4个常用的AnnotationFilter对象的静态变量:
MergedAnnotations静态from方法调用子类TypeMappedAnnotations静态from方法:
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
if (AnnotationsScanner.isKnownEmpty(element, searchStrategy)) {
return NONE;
}
return new TypeMappedAnnotations(element, searchStrategy, repeatableContainers, annotationFilter);
}
下面是TypeMappedAnnotations#get(java.lang.Class)实现代码:
//获取指定类型的最接近的匹配注释或元注释;如果不存在,则获取MergedAnnotation.missing()
@Override
public MergedAnnotation get(Class annotationType) {
return get(annotationType, null, null);
}
@Override
public MergedAnnotation get(Class annotationType,
@Nullable Predicate super MergedAnnotation> predicate) {
return get(annotationType, predicate, null);
}
@Override
public MergedAnnotation get(Class annotationType,
@Nullable Predicate super MergedAnnotation> predicate,
@Nullable MergedAnnotationSelector selector) {
//如果filter命中注解类型,返回一个表示不存在注释的MergedAnnotation
if (this.annotationFilter.matches(annotationType)) {
return MergedAnnotation.missing();
}
MergedAnnotation result = scan(annotationType,
new MergedAnnotationFinder<>(annotationType, predicate, selector));
return (result != null ? result : MergedAnnotation.missing());
}
scan方法参数中传递一个MergedAnnotationFinder对象,MergedAnnotationFinder是接口AnnotationsProcessor的实现类,内部定义了3个用于处理注解的三个方法。
@Nullable
private R scan(C criteria, AnnotationsProcessor processor) {
//如果调用了带有Annotation[]参数的TypeMappedAnnotations#from方法
if (this.annotations != null) {
R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
return processor.finish(result);
}
//调用了带有AnnotatedElement参数的方法
if (this.element != null && this.searchStrategy != null) {
return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
}
return null;
}
调用上面scan方法时,两个if分支的调用过程分别对应下图的两种实例化TypeMappedAnnotations对象。
通过对代码的跟踪发现,这两个分支最终都会调用TypeMappedAnnotations.MergedAnnotationFinder#process这个方法:
@Nullable
private MergedAnnotation process(
Object type, int aggregateIndex, @Nullable Object source, Annotation annotation) {
Annotation[] repeatedAnnotations = repeatableContainers.findRepeatedAnnotations(annotation);
if (repeatedAnnotations != null) {
return doWithAnnotations(type, aggregateIndex, source, repeatedAnnotations);
}
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(
annotation.annotationType(), repeatableContainers, annotationFilter);
for (int i = 0; i < mappings.size(); i++) {
AnnotationTypeMapping mapping = mappings.get(i);
if (isMappingForType(mapping, annotationFilter, this.requiredType)) {
MergedAnnotation candidate = TypeMappedAnnotation.createIfPossible(
mapping, source, annotation, aggregateIndex, IntrospectionFailureLogger.INFO);
if (candidate != null && (this.predicate == null || this.predicate.test(candidate))) {
if (this.selector.isBestCandidate(candidate)) {
return candidate;
}
updateLastResult(candidate);
}
}
}
return null;
}
而对@AliasFor别名的支持就在AnnotationTypeMappings中实现的,具体参考AnnotationTypeMappings和AnnotationTypeMapping源代码。