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

Аннотация компонента Spring @

Автор оригинала: Jordan Simpson.

1. Обзор

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

2. Текст приложения Spring

Прежде чем мы сможем понять значение @Component , мы должны сначала немного разобраться в Spring ApplicationContext . Именно здесь Spring хранит экземпляры объектов, которые он определил для автоматического управления и распространения. Это называется фасоль. Управление компонентами и возможность внедрения зависимостей-вот некоторые из основных функций Spring.

Используя принцип инверсии управления , Spring собирает экземпляры компонентов из нашего приложения и использует их в соответствующее время. Мы можем показать зависимости компонентов для Spring без необходимости обрабатывать настройку и создание экземпляров этих объектов.

Возможность использовать аннотации, такие как @Autowired, для внедрения в наше приложение компонентов, управляемых Spring, является движущей силой для создания мощного и масштабируемого кода в Spring.

Итак, как нам рассказать Весне о бобах, которые мы хотели бы, чтобы она управляла нами? Мы должны воспользоваться автоматическим определением биений Spring, используя аннотации стереотипов в наших классах.

3. @Компонент

@@Component – это аннотация, которая позволяет Spring автоматически определять ваши пользовательские компоненты.

Другими словами, без необходимости писать какой-либо явный код, Spring будет:

  • Сканируйте наше приложение на наличие классов с аннотациями @Component
  • Создайте их экземпляр и внедрите в них любые указанные зависимости
  • Вводите их везде, где это необходимо

Однако большинство разработчиков предпочитают использовать более специализированные аннотации стереотипов для выполнения этой функции.

3.1. Аннотации к Весенним стереотипам

Spring предоставил несколько специализированных аннотаций стереотипов: @Контроллер , @Сервис и @Репозиторий . Все они обеспечивают ту же функцию, что и @Компонент . Причина, по которой все они действуют одинаково, заключается в том, что все они являются составными аннотациями с @Component в качестве мета-аннотации для каждого из них. Они похожи на @Component псевдонимы со специализированным использованием и значением за пределами автоматического обнаружения Spring или внедрения зависимостей.

Если бы мы действительно хотели, мы теоретически могли бы использовать @Component исключительно для наших потребностей в автоматическом обнаружении компонентов. С другой стороны, мы также могли бы составить ваши собственные специализированные аннотации , которые используют @Компонент . Однако существуют и другие области Spring, которые специально ищут специализированные аннотации Spring, чтобы обеспечить дополнительные преимущества автоматизации. Поэтому мы, вероятно, должны просто придерживаться использования установленных специализаций большую часть времени.

Давайте предположим, что у нас есть пример каждого из этих случаев в нашем проекте Spring Boot:

@Controller
public class ControllerExample {
}

@Service
public class ServiceExample {
}

@Repository
public class RepositoryExample {
}

@Component
public class ComponentExample {
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CustomComponent {
}

@CustomComponent
public class CustomComponentExample {
}

Мы могли бы написать тест, который доказывает, что каждый из них автоматически обнаруживается весной и добавляется в ApplicationContext :

@SpringBootTest
@ExtendWith(SpringExtension.class)
public class ComponentUnitTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void givenInScopeComponents_whenSearchingInApplicationContext_thenFindThem() {
        assertNotNull(applicationContext.getBean(ControllerExample.class));
        assertNotNull(applicationContext.getBean(ServiceExample.class));
        assertNotNull(applicationContext.getBean(RepositoryExample.class));
        assertNotNull(applicationContext.getBean(ComponentExample.class));
        assertNotNull(applicationContext.getBean(CustomComponentExample.class));
    }
}

3.2. @ComponentScan

Прежде чем мы полностью положимся на @Component , мы должны понять, что само по себе это всего лишь простая аннотация. Аннотация служит для того, чтобы отличать компоненты от других объектов, таких как объекты домена. Однако Spring использует аннотацию @ComponentScan , чтобы фактически собрать их все в свой ApplicationContext .

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

Однако в случае, если наш @SpringBootApplication класс не может находиться в корне нашего проекта или мы хотим сканировать внешние источники, мы можем явно настроить @ComponentScan для поиска в любом указанном нами пакете, если он существует в пути к классу.

Давайте определим выходящий за рамки @компонент компонент:

package com.baeldung.component.scannedscope;

@Component
public class ScannedScopeExample {
}

Затем мы можем включить его с помощью явных инструкций в нашу @ComponentScan аннотацию:

package com.baeldung.component.inscope;

@SpringBootApplication
@ComponentScan({"com.baeldung.component.inscope", "com.baeldung.component.scannedscope"})
public class ComponentApplication {
    //public static void main(String[] args) {...}
}

Наконец, мы можем проверить, существует ли он:

@Test
public void givenScannedScopeComponent_whenSearchingInApplicationContext_thenFindIt() {
    assertNotNull(applicationContext.getBean(ScannedScopeExample.class));
}

На самом деле это с большей вероятностью произойдет, когда мы захотим проверить наличие внешней зависимости, включенной в наш проект.

3.3. Ограничения @Компонентов

Существуют некоторые сценарии, в которых мы хотим, чтобы определенный объект стал управляемым компонентом Spring, когда мы не можем использовать @Component .

Например, давайте определим объект с аннотацией @Component в пакете за пределами нашего проекта:

package com.baeldung.component.outsidescope;

@Component
public class OutsideScopeExample {
}

Вот тест, который доказывает, что ApplicationContext не включает внешний компонент:

@Test
public void givenOutsideScopeComponent_whenSearchingInApplicationContext_thenFail() {
    assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(OutsideScopeExample.class));
}

Кроме того, у нас может не быть доступа к исходному коду, поскольку он получен из стороннего источника, и мы не можем добавить аннотацию @Component . Или, возможно, мы хотим условно использовать одну реализацию компонента над другой в зависимости от среды, в которой мы работаем. Автоматического обнаружения достаточно большую часть времени, но когда это не так, мы можем использовать @Bean .

4. @Компонент против @Бин

@Bean также является аннотацией, которую Spring использует для сбора компонентов во время выполнения, но она не используется на уровне класса. Скорее, мы аннотируем методы с помощью @Bean , чтобы Spring мог хранить результат метода в виде компонента Spring.

Чтобы увидеть пример того, как это работает, давайте сначала создадим POJO, в котором нет аннотаций:

public class BeanExample {
}

Внутри нашего класса , аннотированного @Configuration , мы можем создать метод генерации компонентов:

@Bean
public BeanExample beanExample() {
    return new BeanExample();
}

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

Затем мы можем написать тест, который подтвердит, что Spring действительно подобрал боб:

@Test
public void givenBeanComponent_whenSearchingInApplicationContext_thenFindIt() {
    assertNotNull(applicationContext.getBean(BeanExample.class));
}

Есть некоторые важные последствия, которые мы должны отметить из-за различий между @Component и @Bean .

  • @Component является аннотацией уровня класса, но @Bean находится на уровне метода, поэтому @Component доступен только в том случае, если исходный код класса доступен для редактирования. @Bean всегда можно использовать, но это более подробно.
  • @Component совместим с автоматическим определением Spring, но @Bean требует создания экземпляра класса вручную.
  • Использование @Bean отделяет создание экземпляра компонента от определения его класса. Вот почему мы можем использовать его для превращения даже сторонних классов в весенние бобы. Это также означает, что мы можем ввести логику, чтобы решить, какой из нескольких возможных вариантов экземпляра для компонента использовать.

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

Мы только что изучили аннотацию Spring @Component , а также другие соответствующие темы. Во-первых, мы обсудили различные аннотации стереотипов Spring, которые являются всего лишь специализированными версиями @Component . Затем мы узнали, что @Component ничего не делает, если его не может найти @ComponentScan . Наконец, поскольку невозможно использовать @Component в классах, для которых у нас нет исходного кода, мы узнали, как вместо этого использовать аннотацию @Bean .

Все эти примеры кода и многое другое можно найти на GitHub .