Spring предоставляет ряд аннотаций с именами, начинающимися с Enable * , по сути, эти аннотации позволяют активировать определенные управляемые функции Spring. Одним хорошим примером такой аннотации является EnableWebMvc, который включает все компоненты, необходимые для поддержки потока MVC в приложениях на основе Spring. Другим хорошим примером является аннотация EnableAsync для активации bean-компонентов для поддержки асинхронных функций в приложениях на основе Spring.
Мне было любопытно, как работают такие аннотации, и я хотел документировать свое понимание. Способ, которым эти аннотации поддерживаются, может считаться частью SPI и поэтому может нарушиться, если внутренняя реализация изменится в будущем.
Простое включение * Аннотации
Один из способов думать об этих пользовательских аннотациях состоит в том, что они добавляют набор новых bean-компонентов в контекст приложения Spring. Давайте начнем с определения одной такой пользовательской аннотации:
|
1
2
3
|
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@interface EnableSomeBeans {} |
и примените эту аннотацию к классу Spring @Configuration:
|
1
2
3
|
@Configuration@EnableSomeBeanspublic static class SpringConfig {} |
Итак, теперь добавить набор bean-компонентов при применении этой аннотации так же просто, как добавить набор bean-компонентов для ввода с помощью аннотации @Import следующим образом:
|
1
2
3
4
|
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Import(SomeBeanConfiguration.class)@interface EnableSomeBeans {} |
По сути, это так, если этот импортированный класс @Configuration определяет какие-либо компоненты, они теперь будут частью контекста приложения:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Configurationclass SomeBeanConfiguration { @Bean public String aBean1() { return "aBean1"; } @Bean public String aBean2() { return "aBean2"; }} |
Вот суть с рабочим образцом.
Включить * аннотации с помощью селекторов
Включить аннотации может быть гораздо сложнее, хотя они могут активировать другое семейство bean-компонентов в зависимости от их окружения. Примером такой аннотации является EnableCaching, который активирует конфигурацию на основе различных реализаций кэширования, доступных в пути к классам.
Написание таких аннотаций Enable * немного сложнее, чем простой пример ранее. Как и прежде, начните с пользовательской аннотации:
|
1
2
3
4
5
6
|
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Import(SomeBeanConfigurationSelector.class)public @interface EnableSomeBeansSelector { String criteria() default "default";} |
Обратите внимание, что в этом случае пользовательская аннотация имеет образец поля, называемого критериями, и я хочу активировать два разных набора компонентов на основе этого критерия. Это может быть достигнуто с помощью селектора @Configuration, который может возвращать другой файл @Configuration в зависимости от контекста (в данном случае это значение поля критериев). Этот селектор имеет простую подпись, и это пример реализации:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import org.springframework.context.annotation.ImportSelector;import org.springframework.core.annotation.AnnotationAttributes;import org.springframework.core.type.AnnotationMetadata;public class SomeBeanConfigurationSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableSomeBeansSelector.class.getName(), false)); String criteria = attributes.getString("criteria"); if (criteria.equals("default")) { return new String[]{"enableannot.selector.SomeBeanConfigurationDefault"}; }else { return new String[]{"enableannot.selector.SomeBeanConfigurationType1"}; } }}@Configurationclass SomeBeanConfigurationType1 { @Bean public String aBean() { return "Type1"; }}@Configurationclass SomeBeanConfigurationDefault { @Bean public String aBean() { return "Default"; }} |
Таким образом, если поле критерия «default», бины в «SomeBeanConfigurationDefault» добавляются, в противном случае — в «SomeBeanConfigurationType1»
- Вот суть с рабочим образцом.
Вывод
Я надеюсь, что это дает понимание того, как Spring внутренне реализует аннотации @ Enable *, так как разработчик приложения может не нуждаться в создании таких аннотаций самостоятельно, более простым механизмом будет использование классов @Configuration и профилей bean-компонентов Spring для создания приложений.
| Ссылка: | Spring Enable annotation — создание пользовательской аннотации Enable от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry. |