Ответ
Spring контейнер хранит экземпляр singleton-бина в своем ApplicationContext (или BeanFactory). Это единственный экземпляр, разделяемый между всеми запросами на этот бин в рамках одного контекста.
Механизм хранения:
- Кеш синглтонов: Контейнер использует внутреннюю карту (
ConcurrentHashMap) для хранения готовых singleton-бинов, где ключом является имя бина. - Создание: При первом запросе (или при eager-инициализации) контейнер создает экземпляр, выполняет инъекцию зависимостей и post-processors, затем помещает его в кеш.
- Повторное использование: Все последующие инъекции (
@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 уникален в рамках своего контекста.