Что происходит если RestController синглтон вызывает сервис с прототипным скоупом в Spring
Что проверяют
Понимаете ли вы, что скоуп бина это про момент создания, а не про момент вызова. Вопрос с подвохом: правильный ответ противоположен интуитивному, и по нему сразу видно, разбирались ли вы с жизненным циклом контейнера или просто расставляли аннотации.
Как отвечать
Контроллер по умолчанию синглтон. Он создаётся один раз, и зависимости в него внедряются один раз, при создании. Значит прототипный сервис будет создан ровно один экземпляр, он попадёт в поле контроллера и проживёт столько же, сколько контроллер. Каждый вызов метода нового экземпляра не создаёт, прототипность фактически теряется.
Если новый экземпляр нужен на каждый вызов, есть рабочие варианты:
- внедрить
ObjectProvider<MyService>илиObjectFactoryи зватьgetObject()в методе; - объявить абстрактный метод с
@Lookup, контейнер подставит реализацию, которая идёт в контекст за новым бином; - поставить прокси:
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS), тогда в поле окажется прокси, а настоящий бин будет запрашиваться при обращении.
Стоит добавить две вещи. Контейнер не управляет уничтожением прототипов: отдал экземпляр и забыл про него, @PreDestroy не вызывается, освобождать ресурсы должен ваш код. И контроллер синглтон, поэтому изменяемое состояние в его полях это гонка между параллельными запросами, а прототип, внедрённый напрямую, никакой изоляции не даёт.
Где спотыкаются
Уверенно отвечают, что на каждый запрос будет свой экземпляр сервиса. Это самая частая ошибка, и дальше собеседование обычно идёт вокруг того, как сделать так, чтобы действительно было по экземпляру.
Тащат applicationContext.getBean прямо в бизнес-код. Работать будет, но класс привязывается к контейнеру и перестаёт собираться в тестах без контекста, провайдер решает то же самое чище.
Ставят прокси и считают вопрос закрытым, не заметив, что с прототипным скоупом новый экземпляр создаётся при каждом обращении к прокси. Если сервис хранит состояние между вызовами методов, оно каждый раз теряется.