Aangepast bereik in het voorjaar

1. Overzicht

Spring biedt uit de doos twee standaard bonen scopes ("Singleton" en "voorlopig ontwerp") die in elke Spring-toepassing kunnen worden gebruikt, plus drie extra bonenkalibers ("verzoek", "sessie", en "GlobalSession") alleen voor gebruik in web-bewuste applicaties.

De standaard bean-scopes kunnen niet worden overschreven en het wordt over het algemeen als een slechte gewoonte beschouwd om de web-bewuste scopes te negeren. Het is echter mogelijk dat u een toepassing heeft die andere of aanvullende mogelijkheden vereist dan die in de meegeleverde scopes.

Als u bijvoorbeeld een systeem met meerdere tenants ontwikkelt, wilt u mogelijk voor elke tenant een afzonderlijk exemplaar van een bepaalde bean of een reeks bonen opgeven. Spring biedt een mechanisme voor het maken van aangepaste scopes voor scenario's zoals deze.

In deze korte tutorial zullen we demonstreren hoe u een aangepast bereik aanmaakt, registreert en gebruikt in een Spring-toepassing.

2. Een aangepaste scopeklasse maken

Om een ​​aangepast bereik te maken, we moeten het Reikwijdte koppel. Daarbij moeten we ook zorg ervoor dat de implementatie thread-safe is omdat scopes door meerdere bonenfabrieken tegelijkertijd kunnen worden gebruikt.

2.1. Beheren van de bereikobjecten en callbacks

Een van de eerste dingen waarmee u rekening moet houden bij het implementeren van een gewoonte Reikwijdte class is hoe u de scoped-objecten en vernietigings-callbacks opslaat en beheert. Dit kan bijvoorbeeld worden gedaan met behulp van een kaart of een speciale klasse.

Voor dit artikel doen we dit op een threadveilige manier met behulp van gesynchroniseerde kaarten.

Laten we beginnen met het definiëren van onze aangepaste scopeklasse:

openbare klasse TenantScope implementeert Scope {private Map scopedObjects = Collections.synchronizedMap (new HashMap ()); private Map destroyCallbacks = Collections.synchronizedMap (nieuwe HashMap ()); ...}

2.2. Een object ophalen uit Scope

Om een ​​object op naam uit ons bereik op te halen, implementeren we de getObject methode. Zoals de JavaDoc stelt, als het benoemde object niet in het bereik bestaat, moet deze methode een nieuw object maken en retourneren.

Bij onze implementatie controleren we of het genoemde object op onze kaart staat. Als dit het geval is, sturen we het terug, en zo niet, dan gebruiken we de ObjectFactory om een ​​nieuw object te maken, voegt u het toe aan onze kaart en retourneert u het:

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

Van de vijf methoden die zijn gedefinieerd door de Reikwijdte koppel, alleen de krijgen methode is vereist om een ​​volledige implementatie te hebben van het beschreven gedrag. De andere vier methoden zijn optioneel en kunnen gooien UnsupportedOperationException als ze een functionaliteit niet nodig hebben of kunnen ondersteunen.

2.3. Een terugroepactie voor vernietiging registreren

We moeten ook het registerDestructionCallback methode. Deze methode biedt een callback die moet worden uitgevoerd wanneer het genoemde object wordt vernietigd of als de scope zelf wordt vernietigd door de toepassing:

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

2.4. Een object uit Scope verwijderen

Laten we vervolgens het verwijderen methode, die het genoemde object uit het bereik verwijdert en ook de geregistreerde vernietigingsoproep verwijdert, waarbij het verwijderde object wordt geretourneerd:

@Override openbaar object remove (String naam) {destructieCallbacks.remove (naam); retourneer scopedObjects.remove (naam); }

Let daar op het is de verantwoordelijkheid van de beller om de callback daadwerkelijk uit te voeren en het verwijderde object te vernietigen.

2.5. De conversatie-ID ophalen

Laten we nu het getConversationId methode. Als uw bereik het concept van een conversatie-ID ondersteunt, zou u deze hier retourneren. Anders is de afspraak om terug te keren nul:

@Override public String getConversationId () {retourneer "tenant"; }

2.6. Contextuele objecten oplossen

Laten we tot slot het resolContextualObject methode. Als uw bereik meerdere contextuele objecten ondersteunt, associeert u elk met een sleutelwaarde en retourneert u het object dat overeenkomt met de opgegeven sleutel parameter. Anders is de afspraak om terug te keren nul:

@Override openbaar object resolContextualObject (String key) {return null; }

3. Registreren van het aangepaste bereik

Om de Spring-container bewust te maken van uw nieuwe scope, moet u dit doen registreer het via de registerScope methode op een ConfigureerbareBeanFactory voorbeeld. Laten we de definitie van deze methode eens bekijken:

void registerScope (String scopeName, Scope scope);

De eerste parameter, scopeName, wordt gebruikt om een ​​bereik te identificeren / specificeren met zijn unieke naam. De tweede parameter, reikwijdte, is een feitelijk exemplaar van de custom Reikwijdte implementatie die u wilt registreren en gebruiken.

Laten we een custom maken BeanFactoryPostProcessor en registreer onze aangepaste scope met een ConfigurableListableBeanFactory:

public class TenantBeanFactoryPostProcessor implementeert BeanFactoryPostProcessor {@Override public void postProcessBeanFactory (ConfigurableListableBeanFactory factory) gooit BeansException {factory.registerScope ("tenant", nieuwe TenantScope ()); }}

Laten we nu een Spring-configuratieklasse schrijven die onze BeanFactoryPostProcessor implementatie:

@Configuration openbare klasse TenantScopeConfig {@Bean openbare statische BeanFactoryPostProcessor beanFactoryPostProcessor () {retourneer nieuwe TenantBeanFactoryPostProcessor (); }}

4. Gebruik van het aangepaste bereik

Nu we onze aangepaste scope hebben geregistreerd, kunnen we deze op al onze bonen toepassen, net zoals we zouden doen met elke andere bean die een andere scope gebruikt dan singleton (het standaardbereik) - door de @Scope annotatie en het specificeren van ons aangepaste bereik op naam.

Laten we een eenvoudig maken TenantBean class - we zullen in een oogwenk bonen met een huurdersbereik van dit type declareren:

openbare klasse TenantBean {private final String name; openbare TenantBean (tekenreeksnaam) {this.name = naam; } public void sayHello () {System.out.println (String.format ("Hallo van% s van het type% s", this.name, this.getClass (). getName ())); }}

Merk op dat we het klassenniveau niet hebben gebruikt @Component en @Scope annotaties over deze klasse.

Laten we nu een aantal bonen met een tenant-bereik definiëren in een configuratieklasse:

@Configuration openbare klasse TenantBeansConfig {@Scope (scopeName = "tenant") @Bean openbare TenantBean foo () {retourneer nieuwe TenantBean ("foo"); } @Scope (scopeName = "tenant") @Bean public TenantBean bar () {retourneer nieuwe TenantBean ("bar"); }}

5. Testen van het aangepaste bereik

Laten we een test schrijven om onze aangepaste scope-configuratie uit te oefenen door een ApplicationContext, het registreren van onze Configuratie klassen en het ophalen van onze bonen met een tenant-bereik:

@Test openbare definitieve leegte whenRegisterScopeAndBeans_thenContextContainsFooAndBar () {AnnotationConfigApplicationContext ctx = nieuwe AnnotationConfigApplicationContext (); probeer {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 (); Kaartfoos = 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 ("tenant")); assertThat (barDefinition.getScope (), equalTo ("tenant")); } ten slotte {ctx.close (); }}

En de output van onze test is:

Hallo van de foo van het type org.baeldung.customscope.TenantBean Hallo van de balk van het type org.baeldung.customscope.TenantBean

6. Conclusie

In deze korte zelfstudie hebben we laten zien hoe u in Spring een aangepast bereik kunt definiëren, registreren en gebruiken.

U kunt meer lezen over aangepaste bereiken in de Spring Framework Reference. U kunt ook een kijkje nemen in de verschillende implementaties van Spring Reikwijdte klassen in de Spring Framework-repository op GitHub.

Zoals gewoonlijk kun je de codevoorbeelden vinden die in dit artikel worden gebruikt in het GitHub-project.


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