Ответ
Один экземпляр на все время жизни singleton-бина. Это ключевая проблема, которую нужно понимать.
Контекст:
- Singleton бин создается контейнером Spring один раз на все приложение.
- Prototype бин должен создаваться новый экземпляр при каждом запросе.
Проблема: Если prototype-бин внедряется в singleton-бин через @Autowired (поле, конструктор, сеттер), то инъекция происходит только один раз — в момент создания singleton-бина. После этого Spring больше не вмешивается, и тот же самый (первоначально внедренный) экземпляр prototype-бина используется на протяжении всей жизни singleton-бина.
Пример, демонстрирующий проблему:
@Component
@Scope("prototype")
public class PrototypeBean {
private final UUID id = UUID.randomUUID();
public UUID getId() { return id; }
}
@Component // По умолчанию scope="singleton"
public class SingletonBean {
@Autowired
private PrototypeBean prototypeBean; // Внедряется ОДИН РАЗ!
public UUID getPrototypeId() {
// Всегда возвращает один и тот же UUID
return prototypeBean.getId();
}
}
Как получить новый prototype при каждом вызове?
- Использование
ApplicationContext(нежелательно, нарушает инверсию управления):@Autowired private ApplicationContext context; public PrototypeBean getNewPrototype() { return context.getBean(PrototypeBean.class); } -
Внедрение
ObjectFactoryилиProvider(рекомендуемый способ):import javax.inject.Provider; // или import org.springframework.beans.factory.ObjectFactory; @Component public class SingletonBean { @Autowired private Provider<PrototypeBean> prototypeBeanProvider; public void process() { PrototypeBean newInstance = prototypeBeanProvider.get(); // Новый бин! } } -
Метод lookup (
@Lookupаннотация):@Component public abstract class SingletonBean { @Lookup protected abstract PrototypeBean createPrototypeBean(); public void process() { PrototypeBean bean = createPrototypeBean(); // Новый бин! } }Вывод: При прямом внедрении (
@Autowired) в singleton будет инжектирован ровно один экземпляр prototype-бина. Для получения нового экземпляра при каждом обращении необходимо использоватьProvider,ObjectFactoryили@Lookup.