Назовите два основных скоупа для бинов в Spring и в чем их отличие
Что проверяют
Знаете ли вы, что скоуп это про время жизни бина и про то, кто отвечает за его уничтожение. Вопрос стартовый, но по ответу видно, работали ли вы со Spring руками: тот, кто только читал про скоупы, обычно не знает про инъекцию prototype в singleton.
Как отвечать
Два основных скоупа это singleton и prototype.
singleton стоит по умолчанию. Контейнер создаёт один экземпляр на контекст и отдаёт одну и ту же ссылку всем, кто его просит. Подходит сервисам, репозиториям, конфигурационным компонентам, то есть всему, что не хранит состояние конкретного запроса.
prototype создаёт новый экземпляр на каждое обращение к контейнеру: на каждый getBean и на каждую инъекцию в другой бин.
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Task task() { return new Task(); }Дальше назовите два настоящих отличия, а не только «один против многих». Первое: полным жизненным циклом контейнер управляет только у синглтона, у прототипа он вызывает инициализацию, отдаёт объект и забывает про него, поэтому @PreDestroy не сработает и ресурсы закрывать вам. Второе: потокобезопасность. Синглтон видят все потоки сразу, изменяемое поле в нём это гонка, а prototype от гонок не спасёт, если ссылку на него сохранили в общем месте.
Полезно упомянуть, что в веб-контексте есть ещё request, session и application.
Где спотыкаются
Говорят, что prototype требует ручного управления памятью. Память освобождает сборщик мусора, как у любого объекта. Ручным остаётся только закрытие ресурсов, потому что колбэки уничтожения для такого бина контейнер не зовёт.
Не знают главной ловушки: если prototype внедрить полем в синглтон, он создастся ровно один раз, вместе с синглтоном, и дальше будет переиспользоваться. Нужен ObjectProvider, @Lookup или прокси через proxyMode.
Путают скоуп бина с состоянием приложения и объявляют prototype там, где по смыслу нужен request. Для данных одного HTTP-запроса скоуп запроса и понятнее, и очищается сам.