Этот вопрос проверяет понимание жизненного цикла бинов в Spring и умение управлять областями видимости (scope) для решения проблемы внедрения зависимостей с разными скоупами.
В Spring Framework область видимости (scope) бина определяет его жизненный цикл и количество создаваемых экземпляров. Singleton — это scope по умолчанию, при котором контейнер IoC создаёт ровно один экземпляр бина на всё приложение. Prototype scope, напротив, приводит к созданию нового экземпляра бина каждый раз, когда он запрашивается из контейнера или внедряется в качестве зависимости.
Если вы внедряете prototype-бин как зависимость в singleton-бин через @Autowired в поле или конструктор, Spring сделает это инъекцию только один раз — во время инициализации singleton-а. В результате singleton получит ссылку на один конкретный экземпляр prototype-бина и будет использовать его постоянно, что противоречит цели scope prototype.
Для получения нового экземпляра prototype-бина внутри singleton-бина при каждом обращении можно использовать следующие подходы:
ApplicationContext в singleton и вызывайте context.getBean(PrototypeBean.class) каждый раз, когда нужен новый экземпляр.@Lookup. Spring подставит реализацию, которая будет возвращать новый prototype-бин.ApplicationContextAware, чтобы получить доступ к контексту и затем запрашивать бины.ObjectFactory<PrototypeBean> или javax.inject.Provider<PrototypeBean>. Их метод getObject() или get() будет возвращать новый экземпляр из контекста.@Component
@Scope("singleton")
public class SingletonService {
private final ObjectFactory<PrototypeBean> prototypeFactory;
@Autowired
public SingletonService(ObjectFactory<PrototypeBean> prototypeFactory) {
this.prototypeFactory = prototypeFactory;
}
public void doWork() {
PrototypeBean freshInstance = prototypeFactory.getObject();
// Используем freshInstance
System.out.println(freshInstance);
}
}
@Component
@Scope("prototype")
public class PrototypeBean {
private final UUID id = UUID.randomUUID();
// ...
}В этом примере каждый вызов doWork() приводит к получению нового экземпляра PrototypeBean с уникальным UUID.
Такая необходимость возникает, когда singleton-сервис должен выполнять операции, требующие изолированного состояния для каждой задачи. Например, обработка HTTP-запроса (где сам сервис — singleton, но для каждого запроса нужен отдельный объект-обработчик), создание временных объектов-строителей (builder) или объектов, хранящих контекст пользовательской сессии.
Вывод: Используйте ObjectFactory/Provider или @Lookup, когда singleton-компоненту необходимо каждый раз получать новый экземпляр prototype-зависимости. Это позволяет сохранить преимущества singleton (производительность, отсутствие состояния) и в то же время использовать свежие объекты с изолированным состоянием, когда это требуется по логике приложения.