1. Обзор
В этом уроке мы узнаем об аннотации @AliasFor
в Spring `` .
Во-первых, мы увидим примеры внутри фреймворка, где он используется. Далее мы рассмотрим несколько индивидуальных примеров.
2. Аннотация
@AliasFor
является частью фреймворка, начиная с версии 4.2. Несколько основных аннотаций Spring были обновлены и теперь включают эту аннотацию.
Мы можем использовать его для оформления атрибутов либо в одной аннотации, либо в аннотации, составленной из мета-аннотации. А именно, мета-аннотация — это аннотация, которую можно применить к другой.
В той же аннотации мы используем @AliasFor
для объявления псевдонимов для атрибутов, чтобы мы могли применять их взаимозаменяемо . В качестве альтернативы мы можем использовать его в составной аннотации, чтобы переопределить атрибут в его мета-аннотации. Другими словами, когда мы декорируем атрибут в составной аннотации с помощью @AliasFor
, он переопределяет указанный атрибут в своей мета-аннотации .
Интересно, что многоядерные аннотации Spring, такие как @Bean
, @ComponentScan
, @Scope
, @RequestMapping
и @RestController
, теперь используют @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 {};
...
}
Как мы видим, значение
здесь определено явно как псевдоним для basePackages
и наоборот. Это означает , что мы можем использовать их взаимозаменяемо .
Таким образом, эти два использования похожи:
@ComponentScan(basePackages = "com.foreach.aliasfor")
@ComponentScan(value = "com.foreach.aliasfor")
Кроме того, поскольку два атрибута также помечены как значения по умолчанию
, давайте напишем это более кратко:
@ComponentScan("com.foreach.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 {};
}
Как мы видим, в @MyMapping действие
является
явным псевдонимом для метода
атрибута в @RequestMapping
. То есть действие
в нашей составленной аннотации переопределяет метод
в мета-аннотации .
Подобно псевдонимам в аннотации, псевдонимы атрибутов метааннотаций также должны иметь один и тот же возвращаемый тип. Например, RequestMethod[]
в нашем случае. Кроме того, аннотация
атрибута должна ссылаться на мета-аннотацию, как в нашем использовании annotation = RequestMapping.class
.
Чтобы продемонстрировать, давайте добавим класс контроллера с именем MyMappingController
. Мы украсим его метод нашей пользовательской аннотацией.
В частности, здесь мы добавим только два атрибута в @MyMapping
, 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);
}
}
}
Как мы видим, действие атрибута нашей пользовательской аннотации переопределило
метод
атрибута мета-аннотации @RequestMapping
. ``
5. Неявные псевдонимы в аннотации
Чтобы понять это, давайте добавим еще несколько псевдонимов в наш @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
являются явными переопределениями мета-аннотаций для пути
в @RequestMapping
. Следовательно, они также являются неявными псевдонимами друг друга. Другими словами, для @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]);
}
}
}
Примечательно, что мы не определяли значение
атрибутов и сопоставление
в аннотации к нашему методу контроллера. Однако они по-прежнему неявно несут то же значение, что и route
.
6. Заключение
В этом уроке мы узнали об аннотации @AliasFor
в Spring Framework . В наших примерах мы рассмотрели как явные, так и неявные сценарии использования.
Как всегда, исходный код доступен на GitHub .