Статьи

Spring Enable annotation — написание пользовательской аннотации Enable

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
@EnableSomeBeans
public 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
@Configuration
class 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"};
        }
    }
}
 
@Configuration
class SomeBeanConfigurationType1 {
 
    @Bean
    public String aBean() {
        return "Type1";
    }
 
}
 
@Configuration
class SomeBeanConfigurationDefault {
 
    @Bean
    public String aBean() {
        return "Default";
    }
 
}

Таким образом, если поле критерия «default», бины в «SomeBeanConfigurationDefault» добавляются, в противном случае — в «SomeBeanConfigurationType1»

  • Вот суть с рабочим образцом.

Вывод

Я надеюсь, что это дает понимание того, как Spring внутренне реализует аннотации @ Enable *, так как разработчик приложения может не нуждаться в создании таких аннотаций самостоятельно, более простым механизмом будет использование классов @Configuration и профилей bean-компонентов Spring для создания приложений.

Ссылка: Spring Enable annotation — создание пользовательской аннотации Enable от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry.