Какие области видимости бинов существуют в Spring?
Что проверяют
Понимаете ли вы, что область видимости задаёт жизненный цикл бина: сколько экземпляров живёт, когда они создаются и кто их уничтожает. Следом обычно спрашивают, потокобезопасен ли синглтон и что станет с prototype внутри синглтона.
Как отвечать
Встроенных областей шесть:
- singleton: по умолчанию. Один экземпляр на
ApplicationContext, создаётся при старте (если нет@Lazy), при закрытии контекста вызывается@PreDestroy; - prototype: новый экземпляр при каждом запросе бина у контейнера,
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE). Контейнер создаёт и настраивает объект, а дальше о нём забывает:@PreDestroyне вызывается; - request: экземпляр на HTTP-запрос;
- session: экземпляр на HTTP-сессию;
- application: экземпляр на
ServletContext; - websocket: экземпляр на WebSocket-сессию.
Последние четыре работают только в веб-контексте. Портлетный globalSession удалён ещё в Spring 5.
Две вещи отличают сильный ответ. Первая: singleton в Spring это не «Одиночка» из GoF. Экземпляр один на контейнер, а не на JVM, и никакой потокобезопасности он не даёт. Поэтому сервисы пишут без изменяемого состояния в полях.
Вторая: prototype, внедрённый в singleton через конструктор, создаётся один раз и дальше живёт как часть синглтона. Чтобы получать свежий экземпляр, берут ObjectProvider<T>, метод с @Lookup или scoped-прокси. Для request и session прокси нужен обязательно, у @RequestScope он включён по умолчанию.
Если спросят про собственную область, назовите интерфейс Scope и регистрацию через ConfigurableBeanFactory.registerScope().
Где спотыкаются
Называют singleton потокобезопасным. Спрингу всё равно, что лежит в полях, и счётчик в поле сервиса под нагрузкой считает неправильно.
Уверены, что prototype в синглтоне будет новым при каждом вызове метода. Он новый при каждом обращении к контейнеру, а внедрение происходит один раз.
Освобождают ресурсы prototype-бина в @PreDestroy и получают утечку: метод не вызовется, закрывать такие ресурсы придётся самому.