Можно ли внедрять prototype-бины в singleton-бины в Spring?

«Можно ли внедрять prototype-бины в singleton-бины в Spring?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, можно, но требуется особая настройка, так как по умолчанию зависимости singleton-бина инжектируются один раз при его создании.

Проблема: Если prototype-бин внедряется в singleton-бин обычным способом (@Autowired), контейнер Spring внедрит его единожды при инициализации singleton-а. В результате singleton будет повторно использовать один и тот же экземпляр prototype-бина, что противоречит его природе.

Решение: Для получения нового экземпляра prototype-бина при каждом обращении необходимо использовать Lookup Method Injection или @Scope("prototype") с proxyMode.

  1. @Lookup (аннотация на метод) - предпочтительный способ для Java-конфигурации:

    @Component
    @Scope("singleton")
    public class SingletonService {
        // Метод, который будет переопределен контейнером
        @Lookup
        public PrototypeBean getPrototypeBean() {
            return null; // Реализация предоставляется Spring
        }
        public void doWork() {
            PrototypeBean bean = getPrototypeBean(); // Каждый вызов возвращает НОВЫЙ экземпляр
            bean.process();
        }
    }
    @Component
    @Scope("prototype")
    public class PrototypeBean { /* ... */ }
  2. Использование ObjectFactory или Provider (более гибкий и явный способ):

    @Component
    @Scope("singleton")
    public class SingletonService {
        @Autowired
        private ObjectFactory<PrototypeBean> prototypeBeanFactory;
        // или private Provider<PrototypeBean> prototypeBeanProvider;
        public void doWork() {
            PrototypeBean bean = prototypeBeanFactory.getObject(); // Новый экземпляр при каждом getObject()
            // PrototypeBean bean = prototypeBeanProvider.get();
            bean.process();
        }
    }

Вывод: Внедрение возможно, но для корректной работы prototype-бина требуется использовать один из механизмов отложенного получения (@Lookup, ObjectFactory, Provider).