知識庫 / Spring RSS 訂閱

Spring 註解別名

Spring
HongKong
5
12:32 PM · Dec 06 ,2025

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 {};
}

如我們所見,在 中,actionmethod 屬性的明確別名,即在 註解中,action 覆蓋了 method 在元註解中的定義。

類似於註解中別名的用法,元註解屬性別名也必須具有相同的返回類型。例如,RequestMethod[] 在我們的例子中。

為了演示,我們添加一個名為 MyMappingController 的控制器類。我們將自定義註解裝飾其方法。

具體來説,我們將只在 中添加兩個屬性,routeaction

@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 {};

在這種情況下,valuemappingroute 是對 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 註解。 在我們的示例中,我們考察了顯式和隱式的使用場景。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.