
Corso di Java Spring Framework #12 | Scope dei bean (singleton)
Iniziamo a parlare dello scope dei bean, un argomento molto importante nell'ambito del framework. Ma di cosa si tratta esattamente?
In parole semplici indica il numero di istanze di un bean presenti all'interno della nostra applicazione.
Ne esistono vari tipi, di cui parleremo più in dettaglio nei prossimi articoli, ma per ora ci occupiamo di quello di default ovvero singleton.
Di fatto Spring crea, in assenza di ulteriori direttive, una singola istanza di ciascun bean e ad ogni richiesta si ottiene sempre il riferimento a tale istanza.
Bisogna comunque fare una piccola precisazione o meglio evidenziare una differenza rispetto all'approccio standard del design pattern Singleton a cui il framework si ispira.
In tale approccio esiste una sola istanza della classe singleton a livello di applicazione.
Infatti il pattern prevede che il costruttore di questo genere di classi sia privato, per cui non siamo noi ad istanziare gli oggetti ma ci serviamo di un opportuno metodo statico che ci restituisce un riferimento all'unica istanza della classe disponibile.
Lo stesso metodo, alla prima invocazione, si occupa di creare l'oggetto.
Spring ha un comportamento leggermente diverso: immaginiamo di avere una classe Veicolo
, simile a quella già vista negli altri esercizi sulla dependency injection.
Se annotiamo questa classe con @Component
(o un'altra annotazione stereotipo) Spring ne crea un'istanza e le attribuisce un nome, detto bean ID, che corrisponderà a quello della classe.
In sostanza avremo una singola istanza all'interno dell'applicazione per cui sembra del tutto simile a quanto avviene con il design pattern singleton tradizionale.
Tuttavia possiamo impostare una classe di configurazione annotata con @Configuration
e creare due o più bean di tipo Veicolo
, ad esempio Veicolo1
e Veicolo2
.
Cosa succede in questo caso?
Ciascun bean è singleton ma in riferimento al nome dell'istanza, ovvero ce ne sarà uno solo di Veicolo1
e altrettanto per Veicolo2
.
Al contrario, rispetto alla classe Veicolo
, ne avremo due differenti.
In un certo senso possiamo dire che il pattern Singleton è appunto un singleton per tipo mentre quello di Spring è un singleton per nome.
Tutto questo vale anche e soprattutto quando si effettua l'injection delle dipendenze.
Il fatto che ci sia comunque una singola istanza per ogni bean pone un problema in scenari reali ovvero applicazioni multithreading in cui possono verificarsi accessi concorrenti da parte di thread differenti.
Questo comporta la necessità di garantire che i bean siano immutabili per evitare che il loro stato possa essere modificato da più parti contemporaneamente, una situazione nota come race condition.
Ovviamente questa situazione deve essere gestita opportunamente per evitare modifiche inattese.
Come risolvere il problema?
In linea di massima si potrebbe ricorrere alla sincronizzazione, come si fa normalmente negli ambienti concorrenti, ma una soluzione del genere nell'ambito dei bean è abbastanza complessa e soprattutto penalizza le performance dell'applicazione.
In effetti i bean singleton non nascono per essere concorrenti ma immutabili, visto che abbiamo una singola istanza. In questo caso non si verifica il problema degli accessi concorrenti.
Ad esempio la dependency injection by constructor ha tra i suoi vantaggi principali quello di poter dichiarare delle dipendenze come final
, ottenendo di fatto una sorta di immutabilità.
Infatti, dopo aver fatto l'assegnazione in fase diciamo di costruzione, questa non può più essere modificata.
Resta inteso che la problematica andrebbe risolta a monte, a livello di progettazione.
Se proprio lo stato dei bean deve essere modificabile forse conviene utilizzare lo scope Prototype che genera una nuova istanza del bean ad ogni richiesta, ma ne parleremo più in dettaglio la prossima volta.
[VIDEO YOUTUBE]
[LINKS]