В чем разница между скоупами Spring бинов Singleton и Prototype и как создаются их экземпляры
Что проверяют
Понимаете ли вы, кто и когда создаёт бин, и знаете ли главную ловушку: prototype внутри синглтона.
Как отвечать
Singleton это значение по умолчанию: один экземпляр на контейнер. Создаётся при старте приложения (для ленивых можно @Lazy), контейнер хранит его до остановки и отдаёт всем, кто просит. Жизненным циклом управляет Spring целиком, включая @PreDestroy.
Prototype: новый экземпляр на каждое обращение к контейнеру. Spring создаёт объект, внедряет зависимости, вызывает инициализацию и после этого забывает о нём: @PreDestroy не вызывается, освобождение ресурсов на вас.
Главная ловушка в том, что область видимости работает на момент внедрения, а не на момент вызова. Внедрили prototype в синглтон, и он создался ровно один раз, вместе с синглтоном:
@Service
public class Report {
private final Formatter formatter; // prototype, но экземпляр один навсегда
}Лечится тремя способами: ObjectProvider<Formatter> с вызовом getObject() в нужный момент, @Lookup-метод или прокси через @Scope(value = "prototype", proxyMode = TARGET_CLASS).
Есть и веб-области: request, session, application. С ними та же проблема и то же решение через прокси.
Где спотыкаются
Не знают, что prototype в синглтоне создаётся один раз.
Ждут вызова @PreDestroy у prototype и оставляют незакрытые ресурсы.
Считают синглтон Spring синглтоном из шаблонов проектирования: у Spring он один на контейнер, а контейнеров в приложении может быть несколько.
Не могут объяснить, чем @Lazy отличается от prototype.