Hurtig guide til Spring Bean Scopes

1. Oversigt

I denne hurtige vejledning lærer du om de forskellige typer bønneromfang i foråret.

Omfanget af en bønne definerer livscyklussen og synligheden for den bønne i de sammenhænge, ​​hvor den bruges.

Den seneste version af Spring Framework definerer 6 typer anvendelsesområder:

  • singleton
  • prototype
  • anmodning
  • session
  • Ansøgning
  • websocket

De sidste fire anvendelsesområder anmodning, session, ansøgning og websocket er kun tilgængelige i et webbaseret program.

2. Singleton Anvendelsesområde

Definition af en bønne med singleton omfang betyder, at containeren opretter en enkelt forekomst af den pågældende bønne, og alle anmodninger om det bønnenavn returnerer det samme objekt, som er cachelagret. Eventuelle ændringer af objektet afspejles i alle referencer til bønnen. Dette omfang er standardværdien, hvis der ikke er angivet et andet omfang.

Lad os oprette en Person enhed til at eksemplificere begrebet omfang:

offentlig klasse person {privat strengnavn; // standard konstruktør, getters og setter}

Bagefter definerer vi bønnen med singleton rækkevidde ved hjælp af @Scope kommentar:

@Bean @Scope ("singleton") offentlig person personSingleton () {returner ny person (); }

Vi kan også bruge en konstant i stedet for Snor værdi på følgende måde:

@Scope (værdi = ConfigurableBeanFactory.SCOPE_SINGLETON)

Nu fortsætter vi med at skrive en test, der viser, at to objekter, der henviser til den samme bønne, vil have de samme værdier, selvom kun en af ​​dem ændrer deres tilstand, da de begge henviser til den samme bønneinstans:

privat statisk endelig String NAME = "John Smith"; @Test offentlig ugyldighed givenSingletonScope_whenSetName_thenEqualNames () {ApplicationContext applicationContext = ny ClassPathXmlApplicationContext ("scopes.xml"); Person personSingletonA = (Person) applicationContext.getBean ("personSingleton"); Person personSingletonB = (Person) applicationContext.getBean ("personSingleton"); personSingletonA.setName (NAME); Assert.assertEquals (NAME, personSingletonB.getName ()); ((AbstractApplicationContext) applicationContext) .close (); }

Det scopes.xml filen i dette eksempel skal indeholde xml-definitionerne af de anvendte bønner:

3. Prototype Anvendelsesområde

En bønne med prototype scope returnerer en anden forekomst hver gang det bliver anmodet om det fra containeren. Det defineres ved at indstille værdien prototype til @Scope kommentar i definitionen af ​​bønner:

@Bean @Scope ("prototype") offentlig person personPrototype () {returner ny person (); }

Vi kunne også bruge en konstant, som vi gjorde for singleton-omfanget:

@Scope (værdi = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

Vi vil nu skrive en lignende test som før, der viser, at to objekter, der anmoder om det samme bønnenavn med prototype, vil have forskellige tilstande, da de ikke længere henviser til den samme bønneinstans:

privat statisk endelig String NAME = "John Smith"; privat statisk endelig String NAME_OTHER = "Anna Jones"; @Test offentlig ugyldighed givenPrototypeScope_whenSetNames_thenDifferentNames () {ApplicationContext applicationContext = ny ClassPathXmlApplicationContext ("scopes.xml"); Person personPrototypeA = (Person) applicationContext.getBean ("personPrototype"); Person personPrototypeB = (Person) applicationContext.getBean ("personPrototype"); personPrototypeA.setName (NAME); personPrototypeB.setName (NAME_OTHER); Assert.assertEquals (NAME, personPrototypeA.getName ()); Assert.assertEquals (NAME_OTHER, personPrototypeB.getName ()); ((AbstractApplicationContext) applicationContext) .close (); } 

Det scopes.xml filen ligner den, der blev præsenteret i det forrige afsnit, mens du tilføjede xml-definitionen for bønnen med prototype rækkevidde:

4. Web-opmærksomme omfang

Som nævnt er der fire ekstra anvendelsesområder, der kun er tilgængelige i en webbevidst applikationskontekst. Disse bruges sjældnere i praksis.

Det anmodning scope opretter en bønneinstans til en enkelt HTTP-anmodning, mens session omfang opretter til en HTTP-session.

Det Ansøgning omfang opretter bønneinstansen for en livscyklus ServletContext og websocket omfang skaber det for et bestemt WebSocket session.

Lad os oprette en klasse, der skal bruges til at instantiere bønnerne:

offentlig klasse HelloMessageGenerator {privat strengbesked; // standard getter og setter}

4.1. Anvendelsesomfang

Vi kan definere bønnen med anmodning anvendelsesområde ved hjælp af @Scope kommentar:

@Bean @Scope (værdi = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) offentlig HelloMessageGenerator requestScopedBean () {returner nye HelloMessageGenerator (); }

Det proxyMode attribut er nødvendig, fordi der i øjeblikket med instantiering af webapplikationens sammenhæng ikke er nogen aktiv anmodning. Spring opretter en proxy, der skal injiceres som en afhængighed, og instantier målbønnen, når det er nødvendigt i en anmodning.

Vi kan også bruge en @RequestScope sammensat kommentar, der fungerer som en genvej til ovenstående definition:

@Bean @RequestScope offentlig HelloMessageGenerator requestScopedBean () {returner ny HelloMessageGenerator (); }

Dernæst kan vi definere en controller, der har en injiceret reference til requestScopedBean. Vi har brug for at få adgang til den samme anmodning to gange for at teste de webspecifikke anvendelsesområder.

Hvis vi viser besked hver gang anmodningen køres, kan vi se, at værdien nulstilles til nul, selvom det senere ændres i metoden. Dette skyldes, at der returneres en anden bønneinstans for hver anmodning.

@Controller offentlig klasse ScopesController {@Resource (name = "requestScopedBean") HelloMessageGenerator requestScopedBean; @RequestMapping ("/ scopes / request") offentlig String getRequestScopeMessage (endelig modelmodel) {model.addAttribute ("previousMessage", requestScopedBean.getMessage ()); requestScopedBean.setMessage ("God morgen!"); model.addAttribute ("currentMessage", requestScopedBean.getMessage ()); returner "scopesExample"; }}

4.2. Sessionsomfang

Vi kan definere bønnen med session rækkevidde på lignende måde:

@Bean @Scope (værdi = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) offentlig HelloMessageGenerator sessionScopedBean () {returner ny HelloMessageGenerator (); }

Der er også en dedikeret sammensat kommentar, som vi kan bruge til at forenkle definitionen af ​​bønner:

@Bean @SessionScope offentlig HelloMessageGenerator sessionScopedBean () {returner ny HelloMessageGenerator (); }

Dernæst definerer vi en controller med en henvisning til sessionScopedBean. Igen skal vi køre to anmodninger for at vise, at værdien af besked felt er det samme for sessionen.

I dette tilfælde, når anmodningen fremsættes for første gang, værdien besked er nul. Men når det først er ændret, bevares denne værdi til efterfølgende anmodninger, da den samme forekomst af bønnen returneres for hele sessionen.

@Controller offentlig klasse ScopesController {@Resource (name = "sessionScopedBean") HelloMessageGenerator sessionScopedBean; @RequestMapping ("/ scopes / session") offentlig String getSessionScopeMessage (endelig modelmodel) {model.addAttribute ("previousMessage", sessionScopedBean.getMessage ()); sessionScopedBean.setMessage ("God eftermiddag!"); model.addAttribute ("currentMessage", sessionScopedBean.getMessage ()); returner "scopesExample"; }}

4.3. Anvendelsesområde

Det Ansøgning omfang opretter bønneinstansen for en livscyklus ServletContext.

Dette svarer til singleton-omfanget, men der er en meget vigtig forskel med hensyn til bønnens omfang.

Når bønner er Ansøgning scoped den samme forekomst af bønnen deles på tværs af flere servletbaserede applikationer, der kører i den samme ServletContext, mens singleton-scoped bønner kun er omfattet af en enkelt applikationskontekst.

Lad os skabe bønnen med Ansøgning rækkevidde:

@Bean @Scope (værdi = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS) offentlig HelloMessageGenerator applicationScopedBean () {returner nye HelloMessageGenerator (); }

Analogt som for anmodning og session rækkevidde, kan vi bruge en kortere version:

@Bean @ApplicationScope offentlig HelloMessageGenerator applicationScopedBean () {returner nye HelloMessageGenerator (); }

Lad os nu oprette en controller, der refererer til denne bønne:

@Controller offentlig klasse ScopesController {@Resource (name = "applicationScopedBean") HelloMessageGenerator applicationScopedBean; @RequestMapping ("/ scopes / application") public String getApplicationScopeMessage (final Model model) {model.addAttribute ("previousMessage", applicationScopedBean.getMessage ()); applicationScopedBean.setMessage ("God eftermiddag!"); model.addAttribute ("currentMessage", applicationScopedBean.getMessage ()); returner "scopesExample"; }}

I dette tilfælde værdi besked en gang sat i applicationScopedBean vil blive bevaret for alle efterfølgende anmodninger, sessioner og endda for en anden servletapplikation, der får adgang til denne bønne, forudsat at den kører i det samme ServletContext.

4.4. WebSocket-omfang

Lad os endelig oprette bønnen med websocket rækkevidde:

@Bean @Scope (scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS) offentlig HelloMessageGenerator websocketScopedBean () {returner nye HelloMessageGenerator (); }

WebSocket-scoped bønner, når de først er adgang, gemmes i WebSocket session attributter. Den samme forekomst af bønnen returneres derefter, når der er adgang til denne bønne i løbet af hele WebSocket session.

Vi kan også sige, at det udviser singleton-adfærd, men begrænset til en WebSocket kun session.

5. Konklusion

Vi har demonstreret forskellige bønneromfang leveret af Spring, og hvad deres tilsigtede anvendelser er.

Implementeringen af ​​denne tutorial kan findes i GitHub-projektet - dette er et Eclipse-baseret projekt, så det skal være let at importere og køre som det er.