Brugerdefineret omfang om foråret

1. Oversigt

Uden for kassen leverer Spring to standard bønneomfang (“Singleton” og “Prototype”), der kan bruges i enhver Spring-applikation plus tre ekstra bønneromfang ("anmodning", "session"og “GlobalSession”) kun til brug i webbevidste applikationer.

Standardbønneomfanget kan ikke tilsidesættes, og det betragtes generelt som en dårlig praksis at tilsidesætte de webbevidste omfang. Du kan dog have en applikation, der kræver forskellige eller yderligere funktioner end dem, der findes i de medfølgende omfang.

Hvis du f.eks. Udvikler et system med flere lejere, kan du muligvis give en separat forekomst af en bestemt bønne eller et sæt bønner til hver lejer. Spring giver en mekanisme til oprettelse af brugerdefinerede omfang for scenarier som dette.

I denne hurtige vejledning demonstrerer vi hvordan man opretter, registrerer og bruger et brugerdefineret omfang i en Spring-applikation.

2. Oprettelse af en brugerdefineret omfangsklasse

For at skabe et brugerdefineret omfang, vi skal gennemføre Anvendelsesområde interface. Ved at gøre det skal vi også sikre, at implementeringen er trådsikker fordi rækkevidde kan bruges af flere bønnefabrikker på samme tid.

2.1. Håndtering af scoped-objekter og tilbagekald

En af de første ting, man skal overveje, når man implementerer en brugerdefineret Anvendelsesområde klasse er, hvordan du gemmer og administrerer genoprettede objekter og ødelæggelsestilbagekald. Dette kan f.eks. Gøres ved hjælp af et kort eller en dedikeret klasse.

Til denne artikel gør vi dette på en trådsikker måde ved hjælp af synkroniserede kort.

Lad os begynde at definere vores brugerdefinerede omfangsklasse:

offentlig klasse TenantScope implementerer Scope {private Map scopedObjects = Collections.synchronizedMap (new HashMap ()); privat kort ødelæggelseCallbacks = Collections.synchronizedMap (ny HashMap ()); ...}

2.2. Henter et objekt fra anvendelsesområdet

For at hente et objekt ved navn fra vores omfang, lad os implementere getObject metode. Som JavaDoc siger, hvis det navngivne objekt ikke findes i omfanget, skal denne metode oprette og returnere et nyt objekt.

I vores implementering kontrollerer vi, om det navngivne objekt er på vores kort. Hvis det er tilfældet, returnerer vi det, og hvis ikke, bruger vi ObjectFactory for at oprette et nyt objekt, tilføje det til vores kort og returnere det:

@Override public Object get (String name, ObjectFactory objectFactory) {if (! ScopedObjects.containsKey (name)) {scopedObjects.put (name, objectFactory.getObject ()); } returner scopedObjects.get (navn); }

Af de fem metoder, der er defineret af Anvendelsesområde interface, kun den metoden kræves for at have en fuld implementering af den beskrevne adfærd. De andre fire metoder er valgfri og kan kaste Ikke-understøttetOperationException hvis de ikke har brug for eller ikke kan understøtte en funktionalitet.

2.3. Registrering af en tilbagekaldelse af destruktion

Vi skal også gennemføre registerDestructionCallback metode. Denne metode giver et tilbagekald, der skal udføres, når det navngivne objekt ødelægges, eller hvis selve omfanget ødelægges af applikationen:

@Override public void registerDestructionCallback (String name, Runnable callback) {destinationCallbacks.put (name, callback); }

2.4. Fjernelse af et objekt fra anvendelsesområdet

Lad os derefter implementere fjerne metode, som fjerner det navngivne objekt fra omfanget og også fjerner dets registrerede tilbagekaldelse af destruktion, og returnerer det fjernede objekt:

@ Override public Object remove (String name) {DestinationCallbacks.remove (name); returner scopedObjects.remove (navn); }

Noter det det er den, der ringer op, faktisk at udføre tilbagekaldet og ødelægge det fjernede objekt.

2.5. Sådan får du samtale-id'et

Lad os nu implementere getConversationId metode. Hvis dit omfang understøtter konceptet med et samtale-id, ville du returnere det her. Ellers er konventionen at vende tilbage nul:

@ Override public String getConversationId () {returner "lejer"; }

2.6. Løsning af kontekstuelle objekter

Lad os endelig implementere resolContextualObject metode. Hvis dit omfang understøtter flere kontekstuelle objekter, forbinder du hver med en nøgleværdi, og du returnerer objektet, der svarer til det angivne nøgle parameter. Ellers er konventionen at vende tilbage nul:

@ Override public Object resolutionContextualObject (strengnøgle) {return null; }

3. Registrering af brugerdefineret rækkevidde

For at gøre Spring Container opmærksom på dit nye anvendelsesområde skal du registrer det gennem registerScope metode på en ConfigurableBeanFactory eksempel. Lad os se på definitionen af ​​denne metode:

ugyldigt registerScope (String scopeName, Scope scope);

Den første parameter, scopeName, bruges til at identificere / specificere et omfang efter dets unikke navn. Den anden parameter, rækkevidde, er en faktisk forekomst af skik Anvendelsesområde implementering, som du ønsker at registrere og bruge.

Lad os oprette en brugerdefineret BeanFactoryPostProcessor og registrer vores brugerdefinerede omfang ved hjælp af en ConfigurableListableBeanFactory:

offentlig klasse TenantBeanFactoryPostProcessor implementerer BeanFactoryPostProcessor {@Override public void postProcessBeanFactory (ConfigurableListableBeanFactory factory) kaster BeansException {factory.registerScope ("lejer", ny TenantScope ()); }}

Lad os nu skrive en Spring-konfigurationsklasse, der indlæser vores BeanFactoryPostProcessor implementering:

@Configuration public class TenantScopeConfig {@Bean public static BeanFactoryPostProcessor beanFactoryPostProcessor () {returner ny TenantBeanFactoryPostProcessor (); }}

4. Brug af brugerdefineret rækkevidde

Nu hvor vi har registreret vores brugerdefinerede anvendelsesområde, kan vi anvende det på alle vores bønner, ligesom vi ville gøre med enhver anden bønne, der bruger et andet omfang end singleton (standardomfanget) - ved hjælp af @Scope annotering og specificering af vores brugerdefinerede omfang ved navn.

Lad os oprette en simpel TenantBean klasse - vi vil erklære lejer-scoped bønner af denne type på et øjeblik:

offentlig klasse TenantBean {privat endelig strengnavn; offentlig TenantBean (strengnavn) {this.name = navn; } offentlig ugyldighed sayHello () {System.out.println (String.format ("Hej fra% s af typen% s", dette.navn, dette.getClass (). getName ())); }}

Bemærk, at vi ikke brugte klasseniveau @Komponent og @Scope kommentarer til denne klasse.

Lad os nu definere nogle lejer-scoped bønner i en konfigurationsklasse:

@Configuration public class TenantBeansConfig {@Scope (scopeName = "tenant") @Bean public TenantBean foo () {returner ny TenantBean ("foo"); } @Scope (scopeName = "lejer") @Bean offentlig TenantBean bar () {returner ny TenantBean ("bar"); }}

5. Test af brugerdefineret rækkevidde

Lad os skrive en test for at udøve vores brugerdefinerede omfangskonfiguration ved at indlæse en ApplicationContext, registrerer vores Konfiguration klasser og hente vores lejer-scoped bønner:

@Test offentlig endelig ugyldig nårRegisterScopeAndBeans_thenContextContainsFooAndBar () {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext (); prøv {ctx.register (TenantScopeConfig.class); ctx.register (TenantBeansConfig.class); ctx.refresh (); TenantBean foo = (TenantBean) ctx.getBean ("foo", TenantBean.class); foo.sayHello (); TenantBean bar = (TenantBean) ctx.getBean ("bar", TenantBean.class); bar.sayHello (); Kort foos = ctx.getBeansOfType (TenantBean.class); hævder, at (foo, ikke (equalTo (bar))); assertThat (foos.size (), equalTo (2)); assertTrue (foos.containsValue (foo)); assertTrue (foos.containsValue (bar)); BeanDefinition fooDefinition = ctx.getBeanDefinition ("foo"); BeanDefinition barDefinition = ctx.getBeanDefinition ("bar"); assertThat (fooDefinition.getScope (), equalTo ("lejer")); assertThat (barDefinition.getScope (), equalTo ("lejer")); } endelig {ctx.close (); }}

Og resultatet fra vores test er:

Hej fra foo af typen org.baeldung.customscope.TenantBean Hej fra bar af typen org.baeldung.customscope.TenantBean

6. Konklusion

I denne hurtige vejledning viste vi, hvordan vi definerer, registrerer og bruger et brugerdefineret omfang i foråret.

Du kan læse mere om brugerdefinerede anvendelsesområder i Spring Framework Reference. Du kan også se på forårets implementeringer af forskellige Anvendelsesområde klasser i Spring Framework-arkivet på GitHub.

Som sædvanligt kan du finde de kodeeksempler, der bruges i denne artikel, over GitHub-projektet.


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