Het verschil tussen CDI en EJB Singleton

1. Overzicht

In deze tutorial gaan we dieper in op twee soorten singletons die beschikbaar zijn in Jakarta EE. We zullen de verschillen uitleggen en demonstreren en zien welke gebruiksmogelijkheden voor elk geschikt zijn.

Laten we eerst eens kijken waar het bij singletons allemaal om draait, voordat we op de details ingaan.

2. Singleton-ontwerppatroon

Bedenk dat een veelgebruikte manier om Singleton Pattern te implementeren is met een statische instantie en een privéconstructor:

openbare laatste klasse Singleton {privé statische laatste Singleton-instantie = nieuwe Singleton (); private Singleton () {} openbare statische Singleton getInstance () {retourinstantie; }} 

Maar helaas, dit is niet echt objectgericht. En het heeft een aantal problemen met multi-threading.

CDI- en EJB-containers bieden ons echter een objectgeoriënteerd alternatief.

3. CDI Singleton

Met CDI (Contexts and Dependency Injection) kunnen we eenvoudig singletons maken met behulp van de @Singleton annotatie. Deze annotatie maakt deel uit van de javax.inject pakket. Het instrueert de container om concretiseer de singleton eenmaal en geeft zijn verwijzing door aan andere objecten tijdens de injectie.

Zoals we kunnen zien, is singleton-implementatie met CDI heel eenvoudig:

@Singleton openbare klasse CarServiceSingleton {// ...} 

Onze klas simuleert een autoservicewinkel. We hebben veel voorbeelden van verschillende Autos, maar ze gebruiken allemaal dezelfde winkel voor onderhoud. Daarom is Singleton een goede match.

We kunnen verifiëren dat het dezelfde instantie is met een eenvoudige JUnit-test die twee keer de context voor de klas vraagt. Merk op dat we een getBean hulpmethode hier voor leesbaarheid:

@Test openbare ongeldig gegevenASingleton_whenGetBeanIsCalledTwice_thenTheSameInstanceIsReturned () {CarServiceSingleton one = getBean (CarServiceSingleton.class); CarServiceSingleton twee = getBean (CarServiceSingleton.class); assertTrue (een == twee); } 

Vanwege de @Singleton annotatie, retourneert de container beide keren dezelfde referentie. Als we dit echter proberen met een gewone beheerde boon, geeft de container elke keer een ander exemplaar.

En terwijl dit voor beide hetzelfde werkt javax.inject.Singleton of javax.ejb.Singleton, er is een belangrijk verschil tussen deze twee.

4. EJB Singleton

Om een ​​EJB-singleton te maken, gebruiken we de @Singleton annotatie van de javax.ejb pakket. Zo creëren we een Singleton Session Bean.

We kunnen deze implementatie op dezelfde manier testen als waarop we de CDI-implementatie in het vorige voorbeeld hebben getest, en het resultaat zal hetzelfde zijn. EJB-singletons leveren, zoals verwacht, de enkele instantie van de klasse.

Echter, EJB Singletons bieden ook extra functionaliteit in de vorm van door containers beheerde gelijktijdigheidscontrole.

Wanneer we dit type implementatie gebruiken, zorgt de EJB-container ervoor dat elke openbare methode van de klasse door één thread tegelijk wordt benaderd. Als meerdere threads dezelfde methode proberen te gebruiken, kan slechts één thread deze gebruiken terwijl andere op hun beurt wachten.

We kunnen dit gedrag verifiëren met een eenvoudige test. We introduceren een servicewachtrij-simulatie voor onze singleton-klassen:

privé statische int serviceQueue; openbare int dienst (auto auto) {serviceQueue ++; Thread.sleep (100); car.setServiced (true); serviceQueue--; retourneer serviceQueue; } 

serviceQueue wordt geïmplementeerd als een gewoon statisch geheel getal dat toeneemt wanneer een auto de dienst "binnenkomt" en afneemt wanneer deze "vertrekt". Als de container een goede vergrendeling geeft, moet deze variabele gelijk zijn aan nul voor en na de service en gelijk aan één tijdens de service.

We kunnen dat gedrag controleren met een eenvoudige test:

@Test public void whenEjb_thenLockingIsProvided () {for (int i = 0; i <10; i ++) {new Thread (new Runnable () {@Override public void run () {int serviceQueue = carServiceEjbSingleton.service (nieuwe auto ("Speedster xyz ")); assertEquals (0, serviceQueue);}}). start (); } terugkeer; } 

Deze test start 10 parallelle threads. Elke thread instantieert een auto en probeert deze te onderhouden. Na de dienst beweert het dat de waarde van de serviceQueue is terug naar nul.

Als we bijvoorbeeld een vergelijkbare test uitvoeren op de CDI-singleton, zal onze test mislukken.

5. Conclusie

In dit artikel hebben we twee soorten singleton-implementaties besproken die beschikbaar zijn in Jakarta EE. We zagen hun voor- en nadelen en we lieten ook zien hoe en wanneer we ze allemaal moesten gebruiken.

En, zoals altijd, is de volledige broncode beschikbaar op GitHub.