Vstrekovanie prototypových bôbov do inštancie Singleton na jar

1. Prehľad

V tomto rýchlom článku si ukážeme rôzne prístupy k vstrekovanie prototypov fazule do jedinej inštancie. Budeme diskutovať o prípadoch použitia a výhodách / nevýhodách každého scenára.

V predvolenom nastavení sú jarné bôby singletony. Problém nastáva, keď sa pokúšame drôtiť fazuľu rôznych rozsahov. Napríklad prototyp fazule do jedného mäsa. Toto je známe akoproblém so vstrekovaním fazule.

Ak sa chcete dozvedieť viac informácií o rozsahu fazule, je dobré začať tým, ako sa dozviete.

2. Problém s injekciou prototypu fazule

Aby sme popísali problém, nakonfigurujme nasledujúce fazule:

@Configuration public class AppConfig {@Bean @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) public PrototypeBean prototypeBean () {return new PrototypeBean (); } @Bean public SingletonBean singletonBean () {vrátiť nový SingletonBean (); }}

Všimnite si, že prvá fazuľa má prototyp rozsahu, druhá je singleton.

Poďme teraz vstreknúť fazuľu s obsahom prototypu do singletonu - a potom vystavíme, ak cez getPrototypeBean () metóda:

verejná trieda SingletonBean {// .. @Autowired private PrototypeBean prototypeBean; public SingletonBean () {logger.info ("Bola vytvorená inštancia Singleton"); } verejné PrototypeBean getPrototypeBean () {logger.info (String.valueOf (LocalTime.now ())); vrátiť prototypBean; }}

Potom nahrajme ApplicationContext a získajte fazuľu singleton dvakrát:

public static void main (String [] args) hodí InterruptedException {AnnotationConfigApplicationContext context = nový AnnotationConfigApplicationContext (AppConfig.class); SingletonBean firstSingleton = context.getBean (SingletonBean.class); PrototypeBean firstPrototype = firstSingleton.getPrototypeBean (); // získaj inštanciu fazule singleton ešte raz SingletonBean secondSingleton = context.getBean (SingletonBean.class); PrototypeBean secondPrototype = secondSingleton.getPrototypeBean (); isTrue (firstPrototype.equals (secondPrototype), "Mala by sa vrátiť rovnaká inštancia"); }

Tu je výstup z konzoly:

Singleton Bean vytvoril prototyp Bean vytvorený 11: 06: 57,894 // mal by tu vytvoriť ďalšiu inštanciu prototypu fazule 11: 06: 58,895

Obidve fazule boli inicializované iba raz, pri štarte kontextu aplikácie.

3. Injekčné ApplicationContext

Môžeme tiež podať injekciu ApplicationContext priamo do fazule.

Ak to chcete dosiahnuť, použite: @Autowire anotáciu alebo implementovať ApplicationContextAware rozhranie:

verejná trieda SingletonAppContextBean implementuje ApplicationContextAware {súkromný ApplicationContext applicationContext; public PrototypeBean getPrototypeBean () {návrat applicationContext.getBean (PrototypeBean.class); } @Override public void setApplicationContext (ApplicationContext applicationContext) hodí BeansException {this.applicationContext = applicationContext; }}

Zakaždým, keď getPrototypeBean () nazýva sa metóda, nová inštancia PrototypeBean bude vrátený z ApplicationContext.

Tento prístup má však vážne nevýhody. Je to v rozpore s princípom inverzie kontroly, pretože závislosti požadujeme priamo od kontajnera.

Taktiež načítame prototyp fazule z applicationContext v rámci SingletonAppcontextBean trieda. To znamenáprepojenie kódu s jarným rámcom.

4. Metóda vstrekovania

Ďalším spôsobom, ako vyriešiť tento problém, je vstrekovanie metódy pomocou @Vyhľadať anotácia:

@ Komponenta public class SingletonLookupBean {@Lookup public PrototypeBean getPrototypeBean () {return null; }}

Jar prekoná getPrototypeBean () metóda anotovaná s @Vyhľadať. Potom zaregistruje fazuľu do kontextu aplikácie. Kedykoľvek požadujeme getPrototypeBean () metóda vráti novú PrototypeBean inštancia.

Na vygenerovanie bytecode použije CGLIB zodpovedný za vyzdvihnutie PrototypeBean z kontextu aplikácie.

5. javax.inject API

Nastavenie spolu s požadovanými závislosťami je popísané v tomto článku o zapojení na jar.

Tu je fazuľa singleton:

verejná trieda SingletonProviderBean {@Autowired private Provider myPrototypeBeanProvider; public PrototypeBean getPrototypeInstance () {return myPrototypeBeanProvider.get (); }}

Používame Poskytovateľrozhranie vstreknúť prototyp fazule. Pre každý getPrototypeInstance () metóda volania, myPrototypeBeanProvider.get () metóda vracia novú inštanciu PrototypeBean.

6. Rozsahovaný proxy server

V predvolenom nastavení má Spring odkaz na skutočný objekt na vykonanie injekcie. Tu vytvoríme objekt proxy, ktorý prepojí skutočný objekt so závislým.

Zakaždým, keď sa zavolá metóda na objekte proxy, server proxy sa sám rozhodne, či vytvorí novú inštanciu skutočného objektu, alebo znovu použije existujúcu.

Aby sme to nastavili, upravíme Appconfig triedy pridať nový @Rozsah anotácia:

@Scope (hodnota = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)

V predvolenom nastavení používa Spring na priame podtriedenie objektov knižnicu CGLIB. Aby sme sa vyhli použitiu CGLIB, môžeme nakonfigurovať režim proxy pomocou ScopedProxyMode.ROZHRANIA, namiesto toho použiť dynamický proxy server JDK.

7. ObjectFactory Rozhranie

Jar poskytuje rozhranie ObjectFactory na výrobu predmetov daného typu na požiadanie:

verejná trieda SingletonObjectFactoryBean {@Autowired private ObjectFactory prototypeBeanObjectFactory; public PrototypeBean getPrototypeInstance () {návrat prototypeBeanObjectFactory.getObject (); }}

Poďme sa na to pozrieť getPrototypeInstance () metóda; getObject () vracia úplne novú inštanciu súboru PrototypeBean pre každú požiadavku. Tu máme väčšiu kontrolu nad inicializáciou prototypu.

Tiež ObjectFactory je súčasťou rámca; to znamená vyhnúť sa ďalšiemu nastavovaniu, aby ste mohli použiť túto možnosť.

8. Vytvorte Bean za behu pomocou java.util.Funkcia

Ďalšou možnosťou je vytvorenie inštancií prototypu fazule za behu, čo nám tiež umožňuje pridať do inštancií parametre.

Aby sme videli príklad, pridajme do nášho poľa s menom PrototypeBean trieda:

verejná trieda PrototypeBean {súkromné ​​meno reťazca; public PrototypeBean (názov reťazca) {this.name = meno; logger.info ("inštancia prototypu" + meno + "vytvorené"); } // ...}

Ďalej vstrekneme fazuľovú továreň do našej singletonovej fazule pomocou produktu java.util.Funkcia rozhranie:

verejná trieda SingletonFunctionBean {@Autowired private Function beanFactory; public PrototypeBean getPrototypeInstance (názov reťazca) {PrototypeBean bean = beanFactory.apply (meno); spätná fazuľa; }}

Nakoniec musíme v našej konfigurácii definovať fazuľa, prototyp a singletonové bôby:

@Configuration verejná trieda AppConfig {@Bean public Function beanFactory () {návratové meno -> prototypeBeanWithParam (meno); } @Bean @Scope (value = "prototype") public PrototypeBean prototypeBeanWithParam (názov reťazca) {vrátiť nový PrototypeBean (názov); } @Bean public SingletonFunctionBean singletonFunctionBean () {vrátiť nový SingletonFunctionBean (); } // ...}

9. Testovanie

Poďme si teraz napísať jednoduchý test JUnit, s ktorým si prípad precvičíme ObjectFactory rozhranie:

@Test public void givenPrototypeInjection_WhenObjectFactory_ThenNewInstanceReturn () {AbstractApplicationContext context = nový AnnotationConfigApplicationContext (AppConfig.class); SingletonObjectFactoryBean firstContext = context.getBean (SingletonObjectFactoryBean.class); SingletonObjectFactoryBean secondContext = context.getBean (SingletonObjectFactoryBean.class); PrototypeBean firstInstance = firstContext.getPrototypeInstance (); PrototypeBean secondInstance = secondContext.getPrototypeInstance (); assertTrue ("Očakáva sa nová inštancia", firstInstance! = secondInstance); }

Po úspešnom spustení testu to vidíme zakaždým getPrototypeInstance () volaná metóda, bola vytvorená nová inštancia prototypu fazule.

10. Záver

V tomto krátkom tutoriáli sme sa naučili niekoľko spôsobov, ako vložiť prototyp fazule do inštancie singleton.

Kompletný kód tohto tutoriálu nájdete ako vždy v projekte GitHub.


$config[zx-auto] not found$config[zx-overlay] not found