1. 概述
在本教程中,我們將學習 @AliasFor 註解在 Spring 中的使用。
首先,我們將查看框架內部的示例,展示其使用情況。接下來,我們將研究一些自定義示例。
2. 註解説明
<em @AliasFor</em> 自 Spring Framework 4.2 版本開始作為框架的一部分。 許多核心 Spring 註解都已更新,現在包含此註解。
我們可以使用它來裝飾屬性,無論是單個註解還是由元註解組成的註解中。 換句話説,元註解是指可以應用於另一個註解的註解。
在同一個註解中,我們使用 <em @AliasFor 來聲明屬性別名,以便我們可以相互替換使用它們。 此外,我們也可以在組合註解中使用它來覆蓋其元註解中的屬性。 換句話説,當我們在組合註解中使用 <em @AliasFor 來裝飾屬性時,它會覆蓋其元註解中指定的屬性。
有趣的是,許多核心 Spring 註解,如 <em @Bean、<em @ComponentScan、<em @Scope、<em @RequestMapping 和 <em @RestController 現在使用 <em @AliasFor 來配置其內部屬性別名。
以下是該註解的定義:
@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;
}重要的是,我們可以隱式地以及明確地使用此標註。
隱式用法僅限於標註內的別名。相比之下,明確用法也可以應用於元標註中的屬性。
在後續章節的示例中,我們將對此進行詳細説明。
3. 標註中顯式別名
讓我們考慮一個核心 Spring 註解 @ComponentScan,以瞭解在單個註解中顯式別名的用法:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
...
}如我們所見, 明確定義為 的別名,反之亦然。這意味着 我們可以互換使用它們。
因此,這些用法實際上非常相似:
@ComponentScan(basePackages = "com.baeldung.aliasfor")
@ComponentScan(value = "com.baeldung.aliasfor")此外,由於這兩個屬性也被標記為default,我們可以更簡潔地寫成:
@ComponentScan("com.baeldung.aliasfor")首先,Spring 強制執行幾個實施要求,以適應此場景。首先,引用屬性應聲明相同的默認值。此外,它們應具有相同的返回類型。如果違反任何這些約束,框架將拋出 AnnotationConfigurationException 異常。
4. 使用元註解中的顯式別名
接下來,讓我們來看一個元註解的示例,並創建一個從該元註解組成的複合註解。然後,我們將看到自定義註解中顯式別名的使用。
首先,讓我們將 RequestMapping 框架註解作為我們的元註解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
...
}接下來,我們將從它創建一個組合註解 MyMapping:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
public @interface MyMapping {
@AliasFor(annotation = RequestMapping.class, attribute = "method")
RequestMethod[] action() default {};
}
如我們所見,在 中,action 是 method 屬性的明確別名,即在 註解中,action 覆蓋了 method 在元註解中的定義。
類似於註解中別名的用法,元註解屬性別名也必須具有相同的返回類型。例如,RequestMethod[] 在我們的例子中。
為了演示,我們添加一個名為 MyMappingController 的控制器類。我們將自定義註解裝飾其方法。
具體來説,我們將只在 中添加兩個屬性,route 和 action:
@Controller
public class MyMappingController {
@MyMapping(action = RequestMethod.PATCH, route = "/test")
public void mappingMethod() {}
}最後,為了觀察顯式別名的行為,我們添加一個簡單的測試:
@Test
public void givenComposedAnnotation_whenExplicitAlias_thenMetaAnnotationAttributeOverridden() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotation = AnnotationUtils.findAnnotation(method, MyMapping.class);
RequestMapping metaAnnotation =
AnnotationUtils.findAnnotation(method, RequestMapping.class);
assertEquals(RequestMethod.PATCH, annotation.action()[0]);
assertEquals(0, metaAnnotation.method().length);
}
}
}如我們所見,我們自定義標註的屬性 action 已經覆蓋了元標註 @RequestMapping 的屬性 method。
5. 註解中的隱式別名
為了理解這一點,讓我們在我們的 @MyMapping 中添加一些額外的別名:
為了理解這一點,讓我們在我們的 @MyMapping 中添加一些額外的別名:
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] value() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] mapping() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] route() default {};在這種情況下,value、mapping 和 route 是對 path 的顯式元註解覆蓋。因此,它們也是彼此的隱式別名。換句話説,@MyMapping, 我們可以使用這三個屬性相互替換。
為了演示這一點,我們將使用上一節中相同的控制器。以下是一個測試用例:
@Test
public void givenComposedAnnotation_whenImplictAlias_thenAttributesEqual() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotationOnBean =
AnnotationUtils.findAnnotation(method, MyMapping.class);
assertEquals(annotationOnBean.mapping()[0], annotationOnBean.route()[0]);
assertEquals(annotationOnBean.value()[0], annotationOnBean.route()[0]);
}
}
}值得注意的是,我們沒有在控制器的註解中定義 <em value 和 <em mapping 屬性。但是,<strong value 和 <strong mapping 仍然隱含地具有與 <em route 相同的價值。
6. 結論
在本教程中,我們學習了 Spring Framework 中的 @AliasFor 註解。 在我們的示例中,我們考察了顯式和隱式的使用場景。