Где и как Spring контейнер хранит singleton-бин?

«Где и как Spring контейнер хранит singleton-бин?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Spring контейнер хранит экземпляр singleton-бина в своем ApplicationContext (или BeanFactory). Это единственный экземпляр, разделяемый между всеми запросами на этот бин в рамках одного контекста.

Механизм хранения:

  1. Кеш синглтонов: Контейнер использует внутреннюю карту (ConcurrentHashMap) для хранения готовых singleton-бинов, где ключом является имя бина.
  2. Создание: При первом запросе (или при eager-инициализации) контейнер создает экземпляр, выполняет инъекцию зависимостей и post-processors, затем помещает его в кеш.
  3. Повторное использование: Все последующие инъекции (@Autowired) или вызовы getBean() возвращают один и тот же объект из кеша.

Область видимости (Scope): По умолчанию все бины в Spring имеют scope singleton. Это можно изменить аннотацией @Scope.

Пример:

@Component // или @Service, @Repository. Scope по умолчанию - "singleton"
public class PaymentService {
    // Один экземпляр на всё приложение
}

@Configuration
public class AppConfig {
    @Bean // Метод @Bean по умолчанию тоже возвращает singleton
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

Важные нюансы:

  • Потокобезопасность: Разработчик сам должен обеспечить потокобезопасность состояния singleton-бина, если к нему обращаются из нескольких потоков.
  • Жизненный цикл: Singleton-бин создается при старте контекста (если не lazy) и уничтожается при закрытии контекста (ContextClosedEvent).
  • Контексты: В веб-приложении могут быть несколько контекстов (Root, Servlet). Singleton уникален в рамках своего контекста.