Egendefinert omfang om våren

1. Oversikt

Uten esken gir Spring to standard bønneanvendelsesområder (“Singleton” og “Prototype”) som kan brukes i en hvilken som helst vårapplikasjon, pluss tre ekstra bønneomfang ("be om", "økt", og “GlobalSession”) kun for bruk i nettbevisste applikasjoner.

Standard bønneomfang kan ikke overstyres, og det anses generelt som en dårlig praksis å overstyre de nettbevisste omfangene. Du kan imidlertid ha et program som krever andre eller tilleggsfunksjoner enn de som finnes i de angitte omfangene.

For eksempel, hvis du utvikler et system med flere leiere, kan det være lurt å oppgi en separat forekomst av en bestemt bønne eller et sett med bønner for hver leietaker. Spring gir en mekanisme for å lage tilpassede omfang for scenarier som dette.

I denne raske opplæringen vil vi demonstrere hvordan du oppretter, registrerer og bruker et tilpasset omfang i en Spring-applikasjon.

2. Opprette en tilpasset omfangsklasse

For å lage et tilpasset omfang, vi må implementere omfang grensesnitt. Når vi gjør det, må vi også sørge for at implementeringen er trådsikker fordi omfang kan brukes av flere bønnefabrikker samtidig.

2.1. Håndtere de omfangsrike objektene og tilbakeringingene

En av de første tingene du bør vurdere når du implementerer en skikk omfang Klassen er hvordan du vil lagre og administrere gjenstandene for gjenstander og ødeleggelser. Dette kan for eksempel gjøres ved hjelp av et kart eller en dedikert klasse.

For denne artikkelen vil vi gjøre dette på en trådsikker måte ved hjelp av synkroniserte kart.

La oss begynne å definere vår tilpassede omfangsklasse:

offentlig klasse TenantScope implementerer Scope {private Map scopedObjects = Collections.synchronizedMap (new HashMap ()); private Map destruksjonCallbacks = Collections.synchronizedMap (ny HashMap ()); ...}

2.2. Henter et objekt fra omfanget

For å hente et objekt etter navn fra vårt omfang, la oss implementere getObject metode. Som JavaDoc sier, Hvis det navngitte objektet ikke finnes i omfanget, må denne metoden opprette og returnere et nytt objekt.

I implementeringen sjekker vi for å se om det navngitte objektet er i kartet vårt. Hvis det er, returnerer vi det, og hvis ikke, bruker vi ObjectFactory for å opprette et nytt objekt, legge det til kartet vårt og returnere det:

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

Av de fem metodene som er definert av omfang grensesnitt, bare den metoden kreves for å ha en full implementering av den beskrevne oppførselen. De andre fire metodene er valgfrie og kan kaste Ikke-støttetOperationException hvis de ikke trenger eller ikke kan støtte en funksjonalitet.

2.3. Registrere en tilbakeringing av destruksjon

Vi må også implementere registerDestructionCallback metode. Denne metoden gir en tilbakeringing som skal utføres når det navngitte objektet blir ødelagt, eller hvis selve omfanget blir ødelagt av applikasjonen:

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

2.4. Fjerne et objekt fra omfanget

La oss deretter implementere fjerne metode, som fjerner det nevnte objektet fra omfanget og også fjerner det registrerte tilbakeringing av ødeleggelse, og returnerer det fjernede objektet:

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

Noter det det er den som ringer å faktisk utføre tilbakeringingen og ødelegge den fjernede gjenstanden.

2.5. Få samtale-ID

La oss nå implementere getConversationId metode. Hvis omfanget ditt støtter begrepet samtale-ID, vil du returnere det hit. Ellers er stevnet å komme tilbake null:

@ Override public String getConversationId () {return "leietaker"; }

2.6. Løse kontekstuelle objekter

Til slutt, la oss implementere løseContextualObject metode. Hvis omfanget ditt støtter flere kontekstuelle objekter, vil du knytte hver til en nøkkelverdi, og du vil returnere objektet som tilsvarer det oppgitte nøkkel parameter. Ellers er stevnet å komme tilbake null:

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

3. Registrering av egendefinert omfang

For å gjøre Spring Container oppmerksom på ditt nye omfang, må du registrer det gjennom registerScope metode på en ConfigurableBeanFactory forekomst. La oss ta en titt på definisjonen av denne metoden:

void registerScope (String scopeName, Scope scope);

Den første parameteren, scopeName, brukes til å identifisere / spesifisere et omfang etter sitt unike navn. Den andre parameteren, omfang, er en faktisk forekomst av skikken omfang implementering som du ønsker å registrere og bruke.

La oss lage en tilpasset BeanFactoryPostProcessor og registrer vårt tilpassede omfang ved hjelp av a ConfigurableListableBeanFactory:

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

La oss nå skrive en vårkonfigurasjonsklasse som laster inn vår BeanFactoryPostProcessor gjennomføring:

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

4. Bruke tilpasset omfang

Nå som vi har registrert vårt tilpassede omfang, kan vi bruke det på hvilken som helst av våre bønner, akkurat som vi ville gjort med andre bønner som bruker et annet omfang enn singleton (standardområdet) - ved å bruke @Omfang kommentar og spesifiserer vårt tilpassede omfang etter navn.

La oss lage en enkel TenantBean klasse - vi vil erklære leietakere av denne typen om et øyeblikk:

offentlig klasse TenantBean {private final String name; offentlig TenantBean (strengnavn) {this.name = navn; } public void sayHello () {System.out.println (String.format ("Hello from% s of type% s", this.name, this.getClass (). getName ())); }}

Merk at vi ikke brukte klassenivået @Komponent og @Omfang kommentarer om denne klassen.

La oss nå definere noen tenant-scoped bønner i en konfigurasjonsklasse:

@Configuration public class TenantBeansConfig {@Scope (scopeName = "tenant") @Bean public TenantBean foo () {return new TenantBean ("foo"); } @Scope (scopeName = "tenant") @Bean public TenantBean bar () {return new TenantBean ("bar"); }}

5. Testing av egendefinert omfang

La oss skrive en test for å utøve vår tilpassede omfangskonfigurasjon ved å laste opp en ApplicationContext, registrerer vår Konfigurasjon klasser, og henting av våre leietakere:

@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 (); Kart foos = ctx.getBeansOfType (TenantBean.class); assertThat (foo, not (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 ("leietaker")); assertThat (barDefinition.getScope (), equalTo ("leietaker")); } til slutt {ctx.close (); }}

Og resultatet fra testen vår er:

Hei fra foo av typen org.baeldung.customscope.TenantBean Hei fra bar av typen org.baeldung.customscope.TenantBean

6. Konklusjon

I denne raske opplæringen viste vi hvordan vi definerer, registrerer og bruker et tilpasset omfang på våren.

Du kan lese mer om tilpassede omfang i Spring Framework Reference. Du kan også ta en titt på vårens implementeringer av forskjellige omfang klasser i Spring Framework repository på GitHub.

Som vanlig kan du finne kodeprøvene som brukes i denne artikkelen på GitHub-prosjektet.


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