L'Inversione di Controllo Spiegata | Spring e le Grandi Architetture

L'inversione del controllo è uno dei concetti più importanti nella programmazione orientata agli oggetti e costituisce la base di architetture popolari come onion, hexagonal e clean architecture.
In questo articolo, risponderò alle seguenti domande:
- Cos'è l'Inversione di Controllo?
- Come viene implementata in Spring?
- Perché è necessaria per le grandi architetture?
Se preferisci ho anche un video che tratta lo stesso argomento spiegandolo con l'ausilio delle animazioni.
Definizione
L'Inversione del Controllo (Inversion of Control, IoC) è un pattern di progettazione che delega la responsabilità di gestire le dipendenze a un framework esterno. Ma cos'è una dipendenza?
Una dipendenza è semplicemente un riferimento a un'altra classe. Ad esempio, una classe di servizio che gestisce i prodotti ha bisogno di un riferimento alla classe di repository interfacciarsi col database. La classe del servizio dipende dal repository, perché non può svolgere le sue funzioni senza di esso.

Gli sviluppatori spesso danno per scontato che queste dipendenze siano risolte da un framework come Spring. Ma cosa succederebbe se ogni classe fosse responsabile di gestire le proprie dipendenze?
Un mondo senza IoC
Il coupling aumenterebbe perché, anziché definire le dipendenze come interfacce, dovremmo fare riferimento a classi concrete. Questo riduce l’information hiding—l'abilità di nascondere i dettagli dell'implementazione dietro interfacce stabili—rendendo difficile cambiare l'implementazione senza condizionare tutte le classi che vi dipendono.

Inoltre, sarebbe anche più complicato condividere una istanza tra più classi. Solitamente, i pool di connessioni al database vengono configurati una volta e condivisi in tutta l'applicazione come singleton. In un mondo senza IoC, l’implementazione del singleton diventa un nostro compito e ogni errore potrebbe portare a istanze duplicate e bug.
Ora che abbiamo capito cos'è l'Inversione di Controllo e perché è importante, vediamo come è implementata in Spring.
Dependency Injection e Bean
Spring implementa una forma specializzata d'Inversione del Controllo chiamata Dependency Injection o DI.
La DI è un pattern in cui gli oggetti dichiarano le proprie dipendenze come metadati di configurazione che vengono poi processati da un framework per creare un sistema completamente configurato.
Spring supporta i metadati di configurazione in diversi formati. I più comuni oggi sono le annotazioni e le classi di configurazione. Tuttavia, è anche possibile definire file XML o script Groovy.
I metadati di configurazione vengono analizzati dal container IoC di Spring e tradotti in BeanDefinitions. Un bean è semplicemente un oggetto che viene creato e gestito dal framework. Come puoi vedere, ci sono diverse proprietà che caratterizzano un bean. Le più importanti sono la classe, il nome e lo scope.

La classe definisce il tipo di bean, mentre il nome viene utilizzato per distinguere istanze diverse dello stesso tipo. Lo scopo determina il ciclo di vita del bean.
Se vogliamo solo un'istanza di un bean, come nel caso di un pool di connessioni al database, impostiamo lo scopo singleton, mentre se vogliamo una nuova istanza ogni volta che un bean viene richiesto, utilizziamo lo scope prototype.
Ci sono anche altri scopi e proprietà del bean, se vuoi più dettagli, lasciami un commento e ne parlerò in un altro articolo. 📃
Ora diamo un'occhiata più da vicino al Container IoC di Spring.
Il Container IoC di Spring
Il Container IoC di Spring è caratterizzato principalmente da due concetti: il BeanFactory
e l'ApplicationContext
.

Il BeanFactory
è l'interfaccia principale; responsabile dell'istanziazione, configurazione e gestione dei bean. In poche parole, implementa la DI.
L'ApplicationContext
estende il BeanFactory e fornisce funzionalità aggiuntive necessarie per configurare completamente l'applicazione secondo le nostre esigenze. Esistono diverse implementazioni dell'ApplicationContext
progettate per supportare diversi formati di configurazione e tipi di applicazioni.
Se sei uno sviluppatore o una sviluppatrice abbastanza giovane, molto probabilmente non hai mai interagito direttamente con l'ApplicationContext
, perché usi Spring Boot.
Spring Boot
Spring Boot's SpringApplication
è un layer aggiuntivo che avvolge il container IoC e configura automaticamente il contesto dell'applicazione, riducendo il bisogno di create configurazioni complesse. A volte basta annotare le nostre classi e i valori di default di Spring Boot sono sufficienti per configurare le connessioni al database, l'autenticazione, l'autorizzazione, la messaggistica e molto altro.
In passato, interagivamo direttamente con questi contesti applicativi. Era molto comune definire tutti i metadati di configurazione come più file XML. Ci voleva abilità e molta pazienza. 😅
Comunque, passiamo all’ultima domanda: perché l’inversione di controllo è necessaria per le grandi architetture (onion, hexagonal e clean architecture)?
L'Inversione di Controllo e le Grandi Architetture
Senza IoC, non è possibile implementare le grandi architetture, perché si basano tutte sullo stesso principio: la logica di business non deve avere dipendenze esterne, come l'interfaccia utente o il database.

Possiamo soddisfare questo requisito solo con un’applicazione meticolosa dell’information hiding. In parole semplici, dobbiamo definire un flusso di controllo in cui le interazioni con il cuore dell'applicazione sono governate dalle interfacce. Spetta poi al framework gestire queste dipendenze a runtime. Senza inversione di controllo ciò non è possibile, perché dovremmo fare riferimento a classi concrete piuttosto che a interfacce.
Se vuoi capire meglio queste grandi architetture, ho un articolo per ciascuna di esse sul mio sito inglese:
Condividi
Se hai letto fin qui, lasciami un commento e condividi per aiutarmi a far crescere il sito e far sì che tutti abbiano l'opportunità di imparare qualcosa di nuovo!
Ciao! 👋