AliasFor Annotation in Spring – Spring中的AliasFor注解

最后修改: 2021年 5月 26日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll learn about the @AliasFor annotation in Spring.

在本教程中,我们将学习Spring中的@AliasFor注解

First, we’ll see examples from within the framework where it’s in use. Next, we’ll look at a few customized examples.

首先,我们将看到框架内的例子,它正在被使用。接下来,我们将看一些定制的例子。

2. The Annotation

2.注释

@AliasFor is part of the framework since version 4.2. Several core Spring annotations have been updated to include this annotation now.

@AliasFor从4.2版本开始是框架的一部分。几个核心的Spring 注释已经被更新,现在包括了这个注释。

We can use it to decorate attributes either within a single annotation or in an annotation composed from a meta-annotation. Namely, a meta-annotation is an annotation that can be applied to another one.

我们可以用它来装饰单个注解中的属性或由元注解组成的注解中的属性。也就是说,一个元注解是一个可以应用于另一个注解的注解。

In the same annotation, we use @AliasFor to declare aliases for attributes so that we can apply them interchangeably. Alternatively, we can use it in a composed annotation to override an attribute in its meta-annotation. In other words, when we decorate an attribute in a composed annotation with @AliasFor, it overrides the specified attribute in its meta-annotation.

在同一个注解中,我们使用@AliasFor来声明属性的别名,以便我们可以互换地应用它们。另外,我们也可以在一个组成的注解中使用它来覆盖其元注解中的一个属性。换句话说,当我们用@AliasFor在组成的注解中装饰一个属性时,它将覆盖其元注解中的指定属性

Interestingly, many-core Spring annotations such as @Bean, @ComponentScan, @Scope, @RequestMapping, and @RestController now use @AliasFor to configure their internal attribute aliases.

有趣的是,许多核心Spring注解,如@Bean@ComponentScan@Scope@RequestMapping@RestController现在使用@AliasFor来配置其内部属性别名。

Here’s the definition of the annotation:

这里是注释的定义。

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

Importantly, we can use this annotation implicitly as well as explicitly. Implicit usage is only restricted to aliases within an annotation. In comparison, explicit usage can also be made for an attribute in a meta-annotation.

重要的是,我们可以隐式地和显式地使用这个注解。隐式使用只限于注解中的别名。相比之下,显式使用也可以用于元注解中的一个属性。

We’ll see this in detail with examples in the following sections.

我们将在下面的章节中通过实例来详细了解这一点。

3. Explicit Aliases Within an Annotation

3.注释中的明确别名

Let’s consider a core Spring annotation, @ComponentScan, to understand explicit aliases within a single annotation:

让我们考虑一个核心的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 {};
...
}

As we can see, value is defined here explicitly as an alias for basePackages, and vice-versa. This means we can use them interchangeably.

我们可以看到,value在这里被明确定义为basePackages的别名,反之亦然。这意味着我们可以互换地使用它们

So effectively, these two usages are similar:

所以实际上,这两种用法是相似的。

@ComponentScan(basePackages = "com.baeldung.aliasfor")

@ComponentScan(value = "com.baeldung.aliasfor")

Furthermore, since the two attributes are also marked as default, let’s write this more concisely:

此外,由于这两个属性也被标记为default,让我们把这个写得更简洁一些。

@ComponentScan("com.baeldung.aliasfor")

Also, there’re a few implementation requirements that Spring mandates for this scenario. First, the aliased attributes should declare the same default value. Additionally, they should have the same return type. If we violate any of these constraints, the framework throws an AnnotationConfigurationException.

另外,Spring为这种情况规定了一些实现要求。首先,别名的属性应该声明相同的默认值。此外,它们应该有相同的返回类型。如果我们违反了这些约束,框架会抛出一个AnnotationConfigurationException

4. Explicit Aliases for Attribute in Meta-Annotation

4.元注释中的属性的明确别名

Next, let’s see an example of a meta-annotation and create a composed annotation from it. Then, we’ll see the explicit usage of aliases in the custom one.

接下来,让我们看一个元注解的例子,并从它创建一个组成注解。然后,我们将看到自定义中别名的明确用法

First, let’s consider the framework annotation RequestMapping as our meta-annotation:

首先,让我们把框架注解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 {};
    ...
}

Next, we’ll create a composed annotation MyMapping from it:

接下来,我们将从中创建一个组成注释MyMapping

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
public @interface MyMapping {
    @AliasFor(annotation = RequestMapping.class, attribute = "method")
    RequestMethod[] action() default {};
}

As we can see, in @MyMapping, action is an explicit alias for the attribute method in @RequestMapping. That is, action in our composed annotation overrides the method in the meta-annotation.

我们可以看到,在@MyMapping中,action@RequestMapping中属性method的明确别名。也就是说,我们组成的注解中的 action 覆盖了元注解中的 method

Similar to aliases within an annotation, meta-annotation attribute aliases must also have the same return type. For example, RequestMethod[] in our case. Furthermore, the attribute annotation should reference the meta-annotation as in our usage of annotation = RequestMapping.class.

与注解中的别名类似,元注解属性别名也必须有相同的返回类型。例如,在我们的例子中,RequestMethod[]。此外,属性annotation应该引用元注解,如我们使用的annotation = RequestMapping.class

To demonstrate, let’s add a controller class called MyMappingController. We’ll decorate its method with our custom annotation.

为了演示,让我们添加一个名为MyMappingController的控制器类。我们将用我们的自定义注解来装饰它的方法。

Specifically, here we’ll add only two attributes to @MyMapping, route, and action:

具体来说,在这里我们只向@MyMapping添加两个属性,route,action

@Controller
public class MyMappingController {

    @MyMapping(action = RequestMethod.PATCH, route = "/test")
    public void mappingMethod() {}
    
}

Finally, to see how explicit aliases behave, let’s add a simple test:

最后,为了看看显式别名是如何表现的,让我们添加一个简单的测试。

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

As we can see, our custom annotation’s attribute action has overridden the meta-annotation @RequestMapping‘s attribute method.

我们可以看到,我们的自定义注解的属性action已经覆盖了元注解@RequestMapping的属性method

5. Implicit Aliases Within an Annotation

5.注释中的隐性别名

To understand this, let’s add a few more aliases within our @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 {};

In this situation, value, mapping, and route are explicit meta-annotation overrides for path in @RequestMapping. Therefore, they are also implicit aliases of each other. In other words, for @MyMapping, we can use these three attributes interchangeably.

在这种情况下,valuemappingroute@RequestMappingpath的显式元注解重写。因此,它们也是彼此的隐式别名。换句话说,对于@MyMapping,我们可以互换地使用这三个属性。

To demonstrate this, we’ll use the same controller as in the previous section. And here’s another test:

为了证明这一点,我们将使用与上一节中相同的控制器。而这里是另一个测试。

@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]);
        }
    }
}

Notably, we did not define the attributes value and mapping in the annotation on our controller method. However, they still implicitly carry the same value as route.

值得注意的是,我们没有在控制器方法的注释中定义属性valuemapping。然而,它们仍然隐含着与route相同的值。

6. Conclusion

6.结语

In this tutorial, we learned about the @AliasFor annotation in the Spring Framework. In our examples, we looked at explicit as well as implicit usage scenarios.

在本教程中,我们了解了Spring框架中的@AliasFor注解。在我们的例子中,我们考察了显式和隐式的使用场景。

As always, source code is available over on GitHub.

一如既往,源代码可在GitHub上获取。