Довольно популярный вопрос на собеседовании — Можно ли внедрить Prototyte в Singleton и как это сделать?
Если просто добавить к определению бина аннотацию @Scope(SCOPE_PROTOTYPE)
, и использовать этот бин в синглтоне через аннотацию @Autowired
– будет создан только один объект. Потому что синглтон создается только однажды, и обращение к прототипу случится тоже однажды при его создании (при внедрении зависимости).
На самом деле вариантов довольно много:
-
с помощью
@Lookup
-
context.getBean(Prototype.class)
-
API -интерфейс javax.inject
-
Интерфейс ObjectFactory
Но эти варианты мягко скажем «не очень».
В некоторых статьях пишут что можно сделать это с помощью параметра ProxyMode в аннотации @Scope, но я не смог найти реальных примеров внедрения, so напишу свой.
Для начала создадим наш будущий Prototype.
-
Каждый раз когда создается новый экземпляр будем выводить в консоль «new bank created».
-
Добавим @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = TARGET_CLASS)
Выражение proxyMode=TARGET_CLASS oзначает, что класс создается с помощью наследования.
Можно сделать proxyMode = INTERFACES, тогда proxy создастся c использованием интерфейсов, наш класс не реализует никаких интерфейсов(интерфейсы — маркеры не подойдут), поэтому используем TARGET_CLASS.
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.util.UUID; import static org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS; /** * Created in SoftMediaLab * by Mark Ponomarev * Date : 15.09.2023 **/ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode=TARGET_CLASS) public class Bank { private final String bankName; public Bank() { this.bankName = UUID.randomUUID().toString(); System.out.println("new bank created"); } public String getInput() { return bankName; } }
Сейчас создадим Singleton.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Created in SoftMediaLab * by Mark Ponomarev * Date : 15.09.2023 **/ @Service() public class BankService { @Autowired Bank bank; public Bank getNewBank(){ return bank; } }
Тут все довольно просто, Мы инжектим наш Prototype c помощью aннотации @Autowired.
Для проверки напишем дополнительный метод.
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class PrimaryExampleApplicationTests { @Autowired BankService messageService; @Test public void testing(){ Bank newBank1 = messageService.getNewBank(); Bank newBank = messageService.getNewBank(); System.out.println(newBank.getInput()); System.out.println(newBank1.getInput()); } }
Можете самостоятельно проверить, что будет создано 2 экземпляра класса Bank.
Для полноты картины вы можете самостоятельно внедрить Prototype, используя динамический Proxy(proxyMode = INTERFACES). Не забудьте про то, что нужно реализовать интерфейс, иначе будет Exeption при поднятии контекста.
ссылка на оригинал статьи https://habr.com/ru/articles/761330/
Добавить комментарий