Рубрики
Без рубрики

Весна @Импорт Аннотации

Узнайте, как и когда использовать аннотацию @Import весной и чем она отличается от @ComponentScan.

Автор оригинала: Gilvan Ornelas.

1. Обзор

В этом уроке мы узнаем как использовать пружину @Import аннотация, уточняя, чем она отличается от @ ComponentScan .

2. Конфигурация и компоненты

Прежде чем понять аннотацию @Import , нам нужно знать, что такое Spring Bean, и иметь базовые рабочие знания аннотации @ Configuration .

Обе темы выходят за рамки этого учебника. Тем не менее, мы можем узнать о них в нашей статье Spring Bean и в документации Spring .

Предположим, что мы уже подготовили три боба – Птица , Кошка и Собака – каждый со своим собственным классом конфигурации.

Затем мы можем предоставить наш контекст с этими Config классами :

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { BirdConfig.class, CatConfig.class, DogConfig.class })
class ConfigUnitTest {

    @Autowired
    ApplicationContext context;

    @Test
    void givenImportedBeans_whenGettingEach_shallFindIt() {
        assertThatBeanExists("dog", Dog.class);
        assertThatBeanExists("cat", Cat.class);
        assertThatBeanExists("bird", Bird.class);
    }

    private void assertThatBeanExists(String beanName, Class beanClass) {
        Assertions.assertTrue(context.containsBean(beanName));
        Assertions.assertNotNull(context.getBean(beanClass));
    }
}

3. Группировка конфигураций с помощью @Import

Нет никаких проблем в объявлении всех конфигураций. Но представьте себе проблему управления десятками классов конфигурации в разных источниках . Должен быть лучший способ.

Аннотация @ Import имеет решение, благодаря своей способности группировать Конфигурации классы:

@Configuration
@Import({ DogConfig.class, CatConfig.class })
class MammalConfiguration {
}

Теперь нам просто нужно вспомнить млекопитающих :

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { MammalConfiguration.class })
class ConfigUnitTest {

    @Autowired
    ApplicationContext context;

    @Test
    void givenImportedBeans_whenGettingEach_shallFindOnlyTheImportedBeans() {
        assertThatBeanExists("dog", Dog.class);
        assertThatBeanExists("cat", Cat.class);

        Assertions.assertFalse(context.containsBean("bird"));
    }

    private void assertThatBeanExists(String beanName, Class beanClass) {
        Assertions.assertTrue(context.containsBean(beanName));
        Assertions.assertNotNull(context.getBean(beanClass));
    }
}

Ну, вероятно, мы скоро забудем нашу Птицу , так что давайте сделаем еще одну группу, чтобы включить все классы конфигурации animal |:

@Configuration
@Import({ MammalConfiguration.class, BirdConfig.class })
class AnimalConfiguration {
}

Наконец-то никто не остался позади, и нам просто нужно запомнить один урок:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { AnimalConfiguration.class })
class AnimalConfigUnitTest {
    // same test validating that all beans are available in the context
}

4. @Import vs @ComponentScan

Прежде чем приступить к примерам @ Import , давайте быстро остановимся и сравним их с @ComponentScan .

4.1. Сходства

Обе аннотации могут принимать любой @Компонент или @Конфигурацию класс.

Давайте добавим новый @ Компонент с помощью @ Импорта :

@Configuration
@Import(Bug.class)
class BugConfig {
}

@Component(value = "bug")
class Bug {
}

Теперь боб Bug доступен так же, как и любой другой боб.

4.2. Концептуальное различие

Проще говоря, мы можем достичь одного и того же результата с обеими аннотациями . Итак, есть ли какая-то разница между ними?

Чтобы ответить на этот вопрос, давайте вспомним, что Spring обычно продвигает подход convention-over-configuration .

Проводя аналогию с нашими аннотациями, @ ComponentScan больше похож на конвенцию, в то время как @ Импорт выглядит как конфигурация .

4.3. Что происходит в реальных приложениях

Как правило, мы запускаем наши приложения с помощью @ ComponentS can в корневом пакете , чтобы он мог найти все компоненты для нас. Если мы используем Spring Boot, то @SpringBootApplication уже включает @ComponentScan , и мы готовы к работе. Это показывает силу конвенции.

Теперь давайте представим, что наше приложение сильно растет. Теперь нам нужно иметь дело с бобами из разных мест, такими как компоненты, различные структуры пакетов и модули, созданные нами самими и третьими сторонами.

В этом случае добавление всего в контекст рискует вызвать конфликты по поводу того, какой компонент использовать. Кроме того, мы можем получить медленное время запуска.

С другой стороны, мы не хотим писать @ Import для каждого нового компонента , потому что это контрпродуктивно.

Возьмем, к примеру, наших животных. Мы действительно могли бы скрыть импорт из контекстного объявления, но нам все равно нужно помнить @ Import для каждого класса Config .

4.4. Совместная работа

Мы можем стремиться к лучшему в обоих мирах. Давайте представим, что у нас есть пакет только для наших животных . Он также может быть компонентом или модулем и сохранять ту же идею.

Тогда у нас может быть один @ компоненты могут только для нашего животного пакета :

package com.baeldung.importannotation.animal;

// imports...

@Configuration
@ComponentScan
public class AnimalScanConfiguration {
}

И @Import to сохраняйте контроль над тем, что мы добавим в контекст:

package com.baeldung.importannotation.zoo;

// imports...

@Configuration
@Import(AnimalScanConfiguration.class)
class ZooApplication {
}

Наконец, любое новое, добавленное в пакет animal, будет автоматически найдено нашим контекстом. И у нас все еще есть явный контроль над конфигурациями, которые мы используем.

5. Заключение

В этом кратком руководстве мы узнали, как использовать @Import для организации наших конфигураций.

Мы также узнали, что @Import очень похож на @ ComponentScan , за исключением того, что @ Import имеет явный подход, в то время как @ ComponentScan использует неявный .

Кроме того, мы рассмотрели возможные трудности управления нашими конфигурациями в реальных приложениях и то, как справиться с ними, объединив обе аннотации.

Как обычно, полный код доступен на GitHub .