Beknopte handleiding voor Spring Bean Scopes

1. Overzicht

In deze korte zelfstudie leert u over de verschillende soorten bean scopes in het Spring-framework.

De reikwijdte van een boon bepaalt de levenscyclus en zichtbaarheid van die boon in de contexten waarin deze wordt gebruikt.

De nieuwste versie van Spring Framework definieert 6 soorten scopes:

  • singleton
  • voorlopig ontwerp
  • verzoek
  • sessie
  • toepassing
  • websocket

De laatste vier genoemde scopes aanvraag, sessie, aanvraag en websocket zijn alleen beschikbaar in een webbewuste applicatie.

2. Singleton-toepassingsgebied

Een boon definiëren met singleton scope betekent dat de container één exemplaar van die bean maakt, en alle aanvragen voor die bean-naam retourneren hetzelfde object, dat in de cache is opgeslagen. Alle wijzigingen aan het object worden weerspiegeld in alle verwijzingen naar de boon. Dit bereik is de standaardwaarde als er geen ander bereik is opgegeven.

Laten we een Persoon entiteit om het concept van scopes te illustreren:

openbare klasse Persoon {privé Stringnaam; // standaard constructor, getters en setters}

Daarna definiëren we de boon met singleton scope met behulp van de @Scope annotatie:

@Bean @Scope ("singleton") publieke Persoon personSingleton () {retourneer nieuwe Persoon (); }

We kunnen ook een constante gebruiken in plaats van de Draad waarde op de volgende manier:

@Scope (waarde = ConfigurableBeanFactory.SCOPE_SINGLETON)

Nu gaan we verder met het schrijven van een test die laat zien dat twee objecten die naar dezelfde bean verwijzen dezelfde waarden zullen hebben, zelfs als slechts één van hen hun status verandert, aangezien ze allebei naar dezelfde bean-instantie verwijzen:

private static final String NAME = "Jan Smit"; @Test openbare ongeldige gegevenSingletonScope_whenSetName_thenEqualNames () {ApplicationContext applicationContext = nieuwe ClassPathXmlApplicationContext ("scopes.xml"); Persoon personSingletonA = (Persoon) applicationContext.getBean ("personSingleton"); Persoon personSingletonB = (Persoon) applicationContext.getBean ("personSingleton"); personSingletonA.setName (NAME); Assert.assertEquals (NAME, personSingletonB.getName ()); ((AbstractApplicationContext) applicationContext) .close (); }

De scopes.xml bestand in dit voorbeeld moet de xml-definities van de gebruikte bonen bevatten:

3. Prototype toepassingsgebied

Een boon met voorlopig ontwerp scope retourneert een ander exemplaar elke keer dat het vanuit de container wordt opgevraagd. Het wordt bepaald door de waarde in te stellen voorlopig ontwerp naar de @Scope annotatie in de bean-definitie:

@Bean @Scope ("prototype") publieke persoon personPrototype () {retourneer nieuwe persoon (); }

We kunnen ook een constante gebruiken zoals we deden voor de singleton-scope:

@Scope (waarde = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

We zullen nu een vergelijkbare test schrijven als voorheen, die laat zien dat twee objecten die dezelfde bean-naam aanvragen met een prototype van een scope verschillende statussen zullen hebben, omdat ze niet langer naar dezelfde bean-instantie verwijzen:

private static final String NAME = "Jan Smit"; private static final String NAME_OTHER = "Anna Jones"; @Test openbare leegte gegevenPrototypeScope_whenSetNames_thenDifferentNames () {ApplicationContext applicationContext = nieuwe ClassPathXmlApplicationContext ("scopes.xml"); Persoon personPrototypeA = (Persoon) applicationContext.getBean ("personPrototype"); Persoon personPrototypeB = (Persoon) applicationContext.getBean ("personPrototype"); personPrototypeA.setName (NAME); personPrototypeB.setName (NAME_OTHER); Assert.assertEquals (NAME, personPrototypeA.getName ()); Assert.assertEquals (NAME_OTHER, personPrototypeB.getName ()); ((AbstractApplicationContext) applicationContext) .close (); } 

De scopes.xml -bestand is vergelijkbaar met het bestand dat in de vorige sectie werd gepresenteerd terwijl de xml-definitie voor de bean werd toegevoegd met voorlopig ontwerp reikwijdte:

4. Webbewuste scopes

Zoals vermeld, zijn er vier extra bereiken die alleen beschikbaar zijn in een webbewuste toepassingscontext. Deze worden in de praktijk minder vaak gebruikt.

De verzoek scope maakt een bean-instantie voor één HTTP-verzoek terwijl session scope creëert voor een HTTP-sessie.

De toepassing scope maakt de bean-instantie voor de levenscyclus van een ServletContext en de websocket scope creëert het voor een bepaald WebSocket sessie.

Laten we een klasse maken om te gebruiken voor het instantiëren van de bonen:

openbare klasse HelloMessageGenerator {privé String-bericht; // standaard getter en setter}

4.1. Verzoek toepassingsgebied

We kunnen de boon definiëren met verzoek scope met behulp van de @Scope annotatie:

@Bean @Scope (waarde = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) openbaar HelloMessageGenerator requestScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

De proxyMode attribuut is nodig omdat er op het moment van de instantiatie van de webapplicatiecontext geen actief verzoek is. Spring zal een proxy maken die als afhankelijkheid moet worden geïnjecteerd, en de doelboon instantiëren wanneer deze nodig is in een verzoek.

We kunnen ook een @RequestScope samengestelde annotatie die fungeert als een snelkoppeling voor de bovenstaande definitie:

@Bean @RequestScope openbare HelloMessageGenerator requestScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Vervolgens kunnen we een controller definiëren met een geïnjecteerde verwijzing naar de requestScopedBean. We hebben twee keer toegang tot hetzelfde verzoek nodig om de webspecifieke scopes te testen.

Als we het bericht elke keer dat het verzoek wordt uitgevoerd, kunnen we zien dat de waarde wordt gereset naar nul, ook al wordt het later in de methode gewijzigd. Dit komt doordat voor elk verzoek een andere bean-instantie wordt geretourneerd.

@Controller openbare klasse ScopesController {@Resource (name = "requestScopedBean") HelloMessageGenerator requestScopedBean; @RequestMapping ("/ scopes / request") public String getRequestScopeMessage (definitief modelmodel) {model.addAttribute ("previousMessage", requestScopedBean.getMessage ()); requestScopedBean.setMessage ("Goedemorgen!"); model.addAttribute ("currentMessage", requestScopedBean.getMessage ()); retourneer "scopesExample"; }}

4.2. Sessiebereik

We kunnen de boon definiëren met sessie scope op een vergelijkbare manier:

@Bean @Scope (waarde = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) openbaar HelloMessageGenerator sessionScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Er is ook een speciale samengestelde annotatie die we kunnen gebruiken om de bean-definitie te vereenvoudigen:

@Bean @SessionScope openbare HelloMessageGenerator sessionScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Vervolgens definiëren we een controller met een verwijzing naar de sessionScopedBean. Nogmaals, we moeten twee verzoeken uitvoeren om aan te tonen dat de waarde van de bericht veld is hetzelfde voor de sessie.

In dit geval, wanneer het verzoek voor de eerste keer wordt gedaan, wordt de waarde bericht is nul. Maar als het eenmaal is gewijzigd, wordt die waarde behouden voor volgende verzoeken, aangezien dezelfde instantie van de bean wordt geretourneerd voor de hele sessie.

@Controller openbare klasse ScopesController {@Resource (name = "sessionScopedBean") HelloMessageGenerator sessionScopedBean; @RequestMapping ("/ scopes / session") public String getSessionScopeMessage (definitief modelmodel) {model.addAttribute ("previousMessage", sessionScopedBean.getMessage ()); sessionScopedBean.setMessage ("Goedemiddag!"); model.addAttribute ("currentMessage", sessionScopedBean.getMessage ()); retourneer "scopesExample"; }}

4.3. Toepassingsgebied

De toepassing scope maakt de bean-instantie voor de levenscyclus van een ServletContext.

Dit is vergelijkbaar met de singleton-scope, maar er is een heel belangrijk verschil met betrekking tot de scope van de boon.

Wanneer bonen zijn toepassing scoped dezelfde instantie van de bean wordt gedeeld door meerdere op servlet gebaseerde applicaties die in dezelfde ServletContext, terwijl bonen met een enkelvoudig bereik slechts tot een enkele toepassingscontext worden beperkt.

Laten we de boon maken met toepassing reikwijdte:

@Bean @Scope (waarde = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS) openbare HelloMessageGenerator applicationScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Analoog als voor de verzoek en sessie scopes kunnen we een kortere versie gebruiken:

@Bean @ApplicationScope openbare HelloMessageGenerator applicationScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Laten we nu een controller maken die naar deze bean verwijst:

@Controller openbare klasse ScopesController {@Resource (name = "applicationScopedBean") HelloMessageGenerator applicationScopedBean; @RequestMapping ("/ scopes / application") openbare String getApplicationScopeMessage (definitief modelmodel) {model.addAttribute ("previousMessage", applicationScopedBean.getMessage ()); applicationScopedBean.setMessage ("Goedemiddag!"); model.addAttribute ("currentMessage", applicationScopedBean.getMessage ()); retourneer "scopesExample"; }}

In dit geval waarde bericht eenmaal ingesteld in de applicationScopedBean wordt bewaard voor alle volgende verzoeken, sessies en zelfs voor een andere servlet-applicatie die toegang heeft tot deze bean, op voorwaarde dat deze in dezelfde ServletContext.

4.4. WebSocket-toepassingsgebied

Laten we tot slot de boon maken met websocket reikwijdte:

@Bean @Scope (scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS) openbaar HelloMessageGenerator websocketScopedBean () {retourneer nieuwe HelloMessageGenerator (); }

Beans met WebSocket-bereik worden bij eerste toegang opgeslagen in het WebSocket sessie attributen. Hetzelfde exemplaar van de boon wordt vervolgens geretourneerd wanneer die boon gedurende de hele periode wordt gebruikt WebSocket sessie.

We kunnen ook zeggen dat het singleton-gedrag vertoont, maar beperkt tot een W.ebSocket alleen sessie.

5. Conclusie

We hebben verschillende bean scopes gedemonstreerd die door Spring worden geleverd en wat hun beoogde gebruik is.

De implementatie van deze tutorial is te vinden in het GitHub-project - dit is een op Eclipse gebaseerd project, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.