La differenza tra CDI e EJB Singleton

1. Panoramica

In questo tutorial, daremo uno sguardo più da vicino a due tipi di singleton disponibili in Jakarta EE. Spiegheremo e dimostreremo le differenze e vedremo gli usi adatti a ciascuno.

Per prima cosa, vediamo cosa sono i singleton prima di entrare nei dettagli.

2. Singleton Design Pattern

Ricorda che un modo comune per implementare Singleton Pattern è con un'istanza statica e un costruttore privato:

public final class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } 

Ma, ahimè, questo non è realmente orientato agli oggetti. E ha alcuni problemi di multi-threading.

Tuttavia, i contenitori CDI e EJB ci offrono un'alternativa orientata agli oggetti.

3. CDI Singleton

Con CDI (Contexts and Dependency Injection), possiamo facilmente creare singleton utilizzando l' annotazione @Singleton . Questa annotazione fa parte del pacchetto javax.inject . Indica al contenitore di creare un'istanza del singleton una volta e passa il suo riferimento ad altri oggetti durante l'iniezione.

Come possiamo vedere, l'implementazione singleton con CDI è molto semplice:

@Singleton public class CarServiceSingleton { // ... } 

La nostra classe simula un negozio di servizi per auto. Abbiamo molte istanze di varie auto , ma tutte usano lo stesso negozio per la manutenzione. Pertanto, Singleton è una buona scelta.

Possiamo verificare che sia la stessa istanza con un semplice test JUnit che richiede due volte il contesto per la classe. Nota che abbiamo un metodo di supporto getBean qui per la leggibilità:

@Test public void givenASingleton_whenGetBeanIsCalledTwice_thenTheSameInstanceIsReturned() { CarServiceSingleton one = getBean(CarServiceSingleton.class); CarServiceSingleton two = getBean(CarServiceSingleton.class); assertTrue(one == two); } 

A causa dell'annotazione @Singleton , il contenitore restituirà lo stesso riferimento entrambe le volte. Se lo proviamo con un bean gestito semplice, tuttavia, il contenitore fornirà ogni volta un'istanza diversa.

E mentre questo funziona allo stesso modo per javax.inject.Singleton o javax.ejb.Singleton, c'è una differenza fondamentale tra questi due.

4. EJB Singleton

Per creare un singleton EJB usiamo l' annotazione @Singleton dal pacchetto javax.ejb . In questo modo creiamo un Singleton Session Bean.

Possiamo testare questa implementazione nello stesso modo in cui abbiamo testato l'implementazione CDI nell'esempio precedente e il risultato sarà lo stesso. I singleton EJB, come previsto, forniscono la singola istanza della classe.

Tuttavia, EJB Singletons fornisce anche funzionalità aggiuntive sotto forma di controllo della concorrenza gestito dal contenitore.

Quando usiamo questo tipo di implementazione, il contenitore EJB garantisce che ogni metodo pubblico della classe sia accessibile da un singolo thread alla volta. Se più thread tentano di accedere allo stesso metodo, solo un thread può utilizzarlo mentre altri aspettano il proprio turno.

Possiamo verificare questo comportamento con un semplice test. Introdurremo una simulazione della coda di servizio per le nostre classi singleton:

private static int serviceQueue; public int service(Car car) { serviceQueue++; Thread.sleep(100); car.setServiced(true); serviceQueue--; return serviceQueue; } 

serviceQueue è implementato come un semplice intero statico che aumenta quando un'auto "entra" nel servizio e diminuisce quando "lascia". Se il blocco viene fornito dal contenitore, questa variabile dovrebbe essere uguale a zero prima e dopo il servizio e uguale a uno durante il servizio.

Possiamo verificare tale comportamento con un semplice 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(new Car("Speedster xyz")); assertEquals(0, serviceQueue); } }).start(); } return; } 

Questo test avvia 10 thread paralleli. Ogni thread crea un'istanza di un'auto e cerca di ripararla. Dopo il servizio, afferma che il valore di serviceQueue è tornato a zero.

Se, ad esempio, eseguiamo un test simile sul singleton CDI, il nostro test fallirà.

5. conclusione

In questo articolo, abbiamo esaminato due tipi di implementazioni singleton disponibili in Jakarta EE. Abbiamo visto i loro vantaggi e svantaggi e abbiamo anche dimostrato come e quando utilizzarli.

E, come sempre, il codice sorgente completo è disponibile su GitHub.