Prototype bonen injecteren in een enkele instantie in het voorjaar

1. Overzicht

In dit korte artikel gaan we verschillende benaderingen van het injecteren van prototype bonen in een enkele instantie. We bespreken de use cases en de voor- / nadelen van elk scenario.

Springbonen zijn standaard singletons. Het probleem doet zich voor wanneer we bonen van verschillende scopes proberen te bedraden. Bijvoorbeeld, een prototype boon in een singleton. Dit staat bekend als descoped bean injectie probleem.

Voor meer informatie over bean scopes is dit artikel een goede plek om te beginnen.

2. Prototype booninjectieprobleem

Laten we de volgende bonen configureren om het probleem te beschrijven:

@Configuration openbare klasse AppConfig {@Bean @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) openbaar PrototypeBean prototypeBean () {retourneer nieuw PrototypeBean (); } @Bean openbare SingletonBean singletonBean () {retourneer nieuwe SingletonBean (); }}

Merk op dat de eerste bean een prototype-scope heeft, de andere is een singleton.

Laten we nu de prototype-scoped bean in de singleton injecteren - en dan blootstellen via de getPrototypeBean () methode:

openbare klasse SingletonBean {// .. @Autowired privé PrototypeBean prototypeBean; openbare SingletonBean () {logger.info ("Singleton-instantie gemaakt"); } openbaar PrototypeBean getPrototypeBean () {logger.info (String.valueOf (LocalTime.now ())); retour prototypeBean; }}

Laten we dan het ApplicationContext en krijg de singleton boon twee keer:

public static void main (String [] args) gooit InterruptedException {AnnotationConfigApplicationContext context = nieuwe AnnotationConfigApplicationContext (AppConfig.class); SingletonBean firstSingleton = context.getBean (SingletonBean.class); PrototypeBean firstPrototype = firstSingleton.getPrototypeBean (); // haal singleton bean instantie nog een keer SingletonBean secondSingleton = context.getBean (SingletonBean.class); PrototypeBean secondPrototype = secondSingleton.getPrototypeBean (); isTrue (firstPrototype.equals (secondPrototype), "Dezelfde instantie moet worden geretourneerd"); }

Hier is de uitvoer van de console:

Singleton Bean gemaakt Prototype Bean gemaakt 11: 06: 57.894 // zou hier een ander prototype bean-instantie moeten maken 11: 06: 58.895

Beide bonen zijn slechts één keer geïnitialiseerd, bij het opstarten van de toepassingscontext.

3. Injecteren ApplicationContext

We kunnen ook de ApplicationContext direct in een boon.

Gebruik hiervoor de @Autowire annotatie of implementeer het ApplicationContextAware koppel:

openbare klasse SingletonAppContextBean implementeert ApplicationContextAware {private ApplicationContext applicationContext; openbare PrototypeBean getPrototypeBean () {return applicationContext.getBean (PrototypeBean.class); } @Override public void setApplicationContext (ApplicationContext applicationContext) gooit BeansException {this.applicationContext = applicationContext; }}

Elke keer dat de getPrototypeBean () methode wordt aangeroepen, een nieuw exemplaar van Prototype Bean zal worden geretourneerd van de ApplicationContext.

Deze benadering heeft echter ernstige nadelen. Het is in tegenspraak met het principe van inversie van controle, aangezien we de afhankelijkheden rechtstreeks van de container opvragen.

We halen ook de prototype-boon op uit de applicationContext binnen de SingletonAppcontextBean klasse. Dit betekenthet koppelen van de code aan het Spring Framework.

4. Methode injectie

Een andere manier om het probleem op te lossen is methode-injectie met de @Opzoeken annotatie:

@Component openbare klasse SingletonLookupBean {@Lookup openbare PrototypeBean getPrototypeBean () {return null; }}

De lente zal de getPrototypeBean () methode geannoteerd met @Opzoeken. Het registreert vervolgens de boon in de toepassingscontext. Telkens wanneer we het getPrototypeBean () methode, retourneert het een nieuw Prototype Bean voorbeeld.

Het zal CGLIB gebruiken om de bytecode te genereren verantwoordelijk voor het ophalen van de Prototype Bean vanuit de toepassingscontext.

5. javax.inject API

De installatie en de vereiste afhankelijkheden worden beschreven in dit artikel over veerbedrading.

Hier is de singleton boon:

openbare klasse SingletonProviderBean {@Autowired privéprovider myPrototypeBeanProvider; openbare PrototypeBean getPrototypeInstance () {retourneer myPrototypeBeanProvider.get (); }}

We gebruiken Aanbiederkoppel om de prototype boon te injecteren. Voor elk getPrototypeInstance () method call, de myPrototypeBeanProvider.get () methode retourneert een nieuw exemplaar van Prototype Bean.

6. Scoped Proxy

Spring bevat standaard een verwijzing naar het echte object om de injectie uit te voeren. Hier maken we een proxy-object om het echte object met het afhankelijke object te verbinden.

Elke keer dat de methode op het proxy-object wordt aangeroepen, beslist de proxy zelf of er een nieuw exemplaar van het echte object moet worden gemaakt of dat het bestaande opnieuw moet worden gebruikt.

Om dit in te stellen, passen we het Appconfig class om een ​​nieuw @Scope annotatie:

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

Spring gebruikt standaard de CGLIB-bibliotheek om de objecten rechtstreeks in subklassen te plaatsen. Om CGLIB-gebruik te vermijden, kunnen we de proxy-modus configureren met ScopedProxyMode.INTERFACES, om in plaats daarvan de JDK dynamische proxy te gebruiken.

7. ObjectFactory Koppel

Spring biedt de ObjectFactory-interface om op aanvraag objecten van het opgegeven type te produceren:

openbare klasse SingletonObjectFactoryBean {@Autowired private ObjectFactory prototypeBeanObjectFactory; openbare PrototypeBean getPrototypeInstance () {retour prototypeBeanObjectFactory.getObject (); }}

Laten we eens kijken getPrototypeInstance () methode; getObject () geeft een gloednieuw exemplaar terug van Prototype Bean voor elk verzoek. Hier hebben we meer controle over de initialisatie van het prototype.

Ook de ObjectFactory maakt deel uit van het raamwerk; dit betekent dat u extra instellingen moet vermijden om deze optie te gebruiken.

8. Creëer een Bean tijdens Runtime met java.util.Functie

Een andere optie is om de prototype bean-instances tijdens runtime te maken, waardoor we ook parameters aan de instances kunnen toevoegen.

Laten we om een ​​voorbeeld hiervan te zien een naamveld toevoegen aan onze Prototype Bean klasse:

openbare klasse PrototypeBean {private String-naam; openbare PrototypeBean (String naam) {this.name = naam; logger.info ("Prototype-instantie" + naam + "aangemaakt"); } // ...}

Vervolgens injecteren we een bonenfabriek in onze singletonboon door gebruik te maken van de java.util.Functie koppel:

openbare klasse SingletonFunctionBean {@Autowired privé Functie beanFactory; openbaar PrototypeBean getPrototypeInstance (Stringnaam) {PrototypeBean bean = beanFactory.apply (naam); terugkeer boon; }}

Ten slotte moeten we de fabrieksbonen, het prototype en de singletonbonen in onze configuratie definiëren:

@Configuration openbare klasse AppConfig {@Bean openbare Functie beanFactory () {retournaam -> prototypeBeanWithParam (naam); } @Bean @Scope (waarde = "prototype") openbaar PrototypeBean prototypeBeanWithParam (String naam) {retourneer nieuw PrototypeBean (naam); } @Bean openbare SingletonFunctionBean singletonFunctionBean () {retourneer nieuwe SingletonFunctionBean (); } // ...}

9. Testen

Laten we nu een eenvoudige JUnit-test schrijven om de case mee te oefenen ObjectFactory koppel:

@Test openbare leegte gegevenPrototypeInjection_WhenObjectFactory_ThenNewInstanceReturn () {AbstractApplicationContext context = nieuwe AnnotationConfigApplicationContext (AppConfig.class); SingletonObjectFactoryBean firstContext = context.getBean (SingletonObjectFactoryBean.class); SingletonObjectFactoryBean secondContext = context.getBean (SingletonObjectFactoryBean.class); PrototypeBean firstInstance = firstContext.getPrototypeInstance (); PrototypeBean secondInstance = secondContext.getPrototypeInstance (); assertTrue ("Nieuw exemplaar verwacht", firstInstance! = secondInstance); }

Nadat we de test met succes hebben gestart, kunnen we dat elke keer zien getPrototypeInstance () methode aangeroepen, een nieuwe prototype bean-instantie gemaakt.

10. Conclusie

In deze korte tutorial hebben we verschillende manieren geleerd om de prototype bean in de singleton-instantie te injecteren.

Zoals altijd is de volledige code voor deze tutorial te vinden op het GitHub-project.


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