Получить доступ

Стереотипы, @Bean и автосвязывание

Стереотипные аннотации и их семантика, @Bean против @Component, component-scan, @Autowired и разрешение неоднозначности.

Стереотипы

@Component помечает класс как бин — Spring находит его через component-scan и сам инстанцирует. @Service, @Repository, @Controller/@RestController — специализации @Component: технически тот же эффект, но семантически обозначают слой.

У @Repository есть и реальное поведение, а не только семантика: он включает exception translation — перевод низкоуровневых исключений JDBC/JPA в единую иерархию Spring DataAccessException (unchecked), чтобы код доступа к данным не зависел от конкретной технологии.

@Bean против @Component

@Component (и специализации) — для СВОИХ классов, которые можно пометить аннотацией. @Bean-метод в @Configuration — для ЧУЖИХ/библиотечных классов, которые пометить нельзя: вы сами создаёте объект и отдаёте контейнеру.

Так конфигурация остаётся явной: свой код сканируется, внешние объекты регистрируются руками (и помните про full mode @Configuration из урока про контекст).

@Configuration
class AppConfig {
    @Bean ObjectMapper objectMapper() { return new ObjectMapper(); } // сторонний класс
}

Component scan

Чтобы стереотипы нашлись, нужен component-scan. В Spring Boot он включён через @SpringBootApplication, который сканирует пакет главного класса и все вложенные — поэтому компоненты обычно держат в том же или нижележащем пакете.

Область и правила настраивают @ComponentScan (basePackages, include/excludeFilters). Частая ошибка новичка — положить бин вне сканируемого пакета и удивляться, что его «нет».

Автосвязывание @Autowired

Внедрение по умолчанию идёт by type: контейнер ищет бин подходящего типа. Если кандидат один — всё просто; на конструкторе с одним вариантом @Autowired даже не нужен.

Если по типу подходящих несколько, Spring пытается разрешить by name (по имени поля/параметра). Если и это не помогает — ошибка NoUniqueBeanDefinitionException на старте.

Разрешение неоднозначности

Когда бинов одного типа несколько, выбор уточняют: @Primary помечает кандидата по умолчанию, а @Qualifier("name") в точке инъекции выбирает конкретного. Можно внедрить и ВСЕ бины типа сразу — как List<Handler> или Map<String, Handler> (имя бина → бин), что удобно для паттерна «стратегия/реестр».

Существуют и стандартные аналоги: @Resource (JSR-250, by name) и @Inject (JSR-330, как @Autowired) — но в Spring-проектах обычно используют @Autowired + @Qualifier.

@Service
class Dispatcher {
    private final Map<String, Handler> handlers; // имя бина -> Handler, все реализации
    Dispatcher(Map<String, Handler> handlers) { this.handlers = handlers; }
}

Как отвечать на собеседовании

Назовите стереотипы и подчеркните, что @Repository не просто семантика, а exception translation в DataAccessException. Различите @Component (свой класс, скан) и @Bean (чужой класс, @Configuration). Объясните автосвязывание (by type → by name) и разрешение конфликтов (@Primary/@Qualifier, а также инъекцию List/Map всех бинов типа). Упомяните типичную ошибку с пакетом вне component-scan.

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем