Intro to Inversion of Control and Dependency Injection with Spring

Intro to Inversion of Control and Dependency Injection with Spring

Overview

In questo articolo, introdurremo i concetti di IoC (Inversion of Control) e DI (Dependency Injection), e poi daremo un’occhiata a come questi sono implementati nel framework Spring.,

Ulteriori letture:

Cablaggio in primavera: @Autowired, @Resource e @Inject

Questo articolo confronterà e contrapporrà l’uso delle annotazioni relative all’iniezione delle dipendenze, vale a dire le annotazioni @Resource, @Inject e @Autowired.
Per saperne di più →

@Component vs @Repository e @Service in Spring

Scopri le differenze tra le annotazioni @Component, @Repository e @Service e quando usarle.
Per saperne di più →

Che cos’è l’inversione del controllo?,

L’inversione del controllo è un principio nell’ingegneria del software mediante il quale il controllo di oggetti o porzioni di un programma viene trasferito in un contenitore o framework. È più spesso utilizzato nel contesto della programmazione orientata agli oggetti.

In contrasto con la programmazione tradizionale, in cui il nostro codice personalizzato effettua chiamate a una libreria, IoC consente a un framework di prendere il controllo del flusso di un programma ed effettuare chiamate al nostro codice personalizzato. Per abilitare ciò, i framework utilizzano astrazioni con un comportamento aggiuntivo incorporato., Se vogliamo aggiungere il nostro comportamento, dobbiamo estendere le classi del framework o plugin le nostre classi.,

I vantaggi di questa architettura sono:

  • disaccoppiamento, l’esecuzione di un compito dalla sua applicazione
  • il che rende più facile per passare tra le diverse implementazioni
  • maggiore modularità di un programma.
  • la maggiore facilità nel test di un programma con l’isolamento di un componente o di un beffardo sue dipendenze e permettendo la comunicazione dei componenti attraverso i contratti

Inversione del Controllo può essere raggiunto attraverso diversi meccanismi, come: Strategia di design pattern, Service Locator modello, modello Factory, e la Dependency Injection (DI).,

Stiamo andando a guardare DI prossimo.

Che cos’è l’iniezione di dipendenza?

Dependency injection è un modello attraverso il quale implementare IoC, in cui il controllo invertito è l’impostazione delle dipendenze dell’oggetto.

L’atto di collegare oggetti con altri oggetti, o “iniettare” oggetti in altri oggetti, è fatto da un assemblatore piuttosto che dagli oggetti stessi.,

Ecco come si creerebbe una dipendenza da oggetti nella programmazione tradizionale:

public class Store { private Item item; public Store() { item = new ItemImpl1(); }}

Nell’esempio sopra, dobbiamo istanziare un’implementazione dell’interfaccia Item all’interno della classe Store stessa.

Utilizzando DI, possiamo riscrivere l’esempio senza specificare l’implementazione di Item che vogliamo:

public class Store { private Item item; public Store(Item item) { this.item = item; }}

Nelle prossime sezioni, vedremo come possiamo fornire l’implementazione di Item attraverso i metadati.,

Sia IoC che DI sono concetti semplici, ma hanno profonde implicazioni nel modo in cui strutturiamo i nostri sistemi, quindi vale la pena capirli bene.

Il contenitore IoC Spring

Un contenitore IoC è una caratteristica comune dei framework che implementano IoC.

Nel framework Spring, il contenitore IoC è rappresentato dall’interfaccia ApplicationContext. Il contenitore Spring è responsabile dell’istanziazione, configurazione e assemblaggio di oggetti noti come bean, nonché della gestione del loro ciclo di vita.,

Il framework Spring fornisce diverse implementazioni dell’interfaccia ApplicationContext — ClassPathXmlApplicationContext e FileSystemXmlApplicationContext per le applicazioni standalone e WebApplicationContext per le applicazioni Web.

Per assemblare i bean, il contenitore utilizza i metadati di configurazione, che possono essere sotto forma di configurazione XML o annotazioni.

Ecco un modo per istanziare manualmente un contenitore:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Per impostare l’attributo item nell’esempio sopra, possiamo usare i metadati., Quindi, il contenitore leggerà questi metadati e lo utilizzerà per assemblare i bean in fase di runtime.

L’iniezione di dipendenza in primavera può essere eseguita tramite costruttori, setter o campi.

Iniezione di dipendenze basata sul costruttore

Nel caso di iniezione di dipendenze basata sul costruttore, il contenitore invocherà un costruttore con argomenti che rappresentano ciascuno una dipendenza che vogliamo impostare.

Spring risolve ogni argomento principalmente per tipo, seguito dal nome dell’attributo e dall’indice per la disambiguazione., Vediamo la configurazione di un bean e le sue dipendenze usando le annotazioni:

L’annotazione @ Configuration indica che la classe è una fonte di definizioni di bean. Inoltre, possiamo aggiungerlo a più classi di configurazione.

L’annotazione @Bean viene utilizzata su un metodo per definire un bean. Se non specifichiamo un nome personalizzato, il nome del bean sarà predefinito per il nome del metodo.

Per un bean con l’ambito singleton predefinito, Spring controlla prima se esiste già un’istanza memorizzata nella cache del bean e ne crea una nuova solo se non lo fa., Se stiamo usando l’ambito del prototipo, il contenitore restituisce una nuova istanza bean per ogni chiamata al metodo.

Un altro modo per creare la configurazione dei bean è attraverso la configurazione XML:

Setter-Based Dependency Injection

Per setter-based DI, il contenitore chiamerà i metodi setter della nostra classe, dopo aver richiamato un costruttore no-argument o no-argument static factory method per istanziare il bean., Creiamo questa configurazione usando le annotazioni:

@Beanpublic Store store() { Store store = new Store(); store.setItem(item1()); return store;}

Possiamo anche usare XML per la stessa configurazione dei bean:

<bean class="org.baeldung.store.Store"> <property name="item" ref="item1" /></bean>

I tipi di iniezione basati su costruttori e setter possono essere combinati per lo stesso bean. La documentazione Spring consiglia di utilizzare l’iniezione basata sul costruttore per le dipendenze obbligatorie e l’iniezione basata sul setter per quelle facoltative.

7., Field-Based Dependency Injection

In caso di Field-Based DI, possiamo iniettare le dipendenze contrassegnandole con un’annotazione @Autowired:

public class Store { @Autowired private Item item; }

Durante la costruzione dell’oggetto Store, se non esiste un costruttore o un metodo setter per iniettare il bean Item, il contenitore userà reflection per iniettare Item in Store.

Possiamo anche ottenere questo utilizzando la configurazione XML.,

Questo approccio potrebbe sembrare più semplice e pulito, ma non è raccomandato l’uso perché ha alcuni inconvenienti come:

  • Questo metodo utilizza reflection per iniettare le dipendenze, che è più costoso dell’iniezione basata sul costruttore o sul setter
  • È davvero facile continuare ad aggiungere più dipendenze usando questo approccio. Se si stesse usando l’iniezione del costruttore con più argomenti ci avrebbe fatto pensare che la classe fa più di una cosa che può violare il principio di responsabilità singola.,

Ulteriori informazioni sull’annotazione @Autowired possono essere trovate nell’articolo Wiring In Spring.

Dipendenze di Autowiring

Il cablaggio consente al contenitore Spring di risolvere automaticamente le dipendenze tra i bean che collaborano ispezionando i bean che sono stati definiti.,

Ci sono quattro modalità di autowiring un fagiolo utilizzando una configurazione XML:

  • no: il valore di default è – questo significa che non autowiring è utilizzato per il fagiolo e abbiamo esplicitamente il nome delle dipendenze
  • nome: autowiring viene effettuato in base al nome della proprietà, pertanto Primavera cercherà un bean con lo stesso nome della proprietà che deve essere impostato
  • byType: simile al nome autowiring, solo in base al tipo di struttura. Ciò significa che Spring cercherà un bean con lo stesso tipo di proprietà da impostare., Se c’è più di un bean di quel tipo, il framework genera un’eccezione.,può anche iniettare fagioli usando l’annotazione @Autowired per autowiring per tipo:
    public class Store { @Autowired private Item item;}

    Se c’è più di un fagiolo dello stesso tipo, si può utilizzare il @Qualifier annotazione di riferimento di un bean per nome:

    public class Store { @Autowired @Qualifier("item1") private Item item;}

    Ora, diciamo autowire fagioli dal tipo di configurazione XML:

    <bean class="org.baeldung.store.Store" autowire="byType"> </bean>

    passiamo ad iniettare un bean denominato voce in voce, di proprietà di negozio chicco per nome tramite XML:

    <bean class="org.baeldung.store.ItemImpl1" /><bean class="org.baeldung.store.Store" autowire="byName"></bean>

    Si può anche sostituire la autowiring definendo dipendenze attraverso argomenti del costruttore o setter.,

    Lazy Initialized Bean

    Per impostazione predefinita, il contenitore crea e configura tutti i bean singleton durante l’inizializzazione. Per evitare ciò, è possibile utilizzare l’attributo lazy-init con valore true nella configurazione del bean:

    <bean class="org.baeldung.store.ItemImpl1" lazy-init="true" />

    Di conseguenza, il bean item1 verrà inizializzato solo quando viene richiesto per la prima volta e non all’avvio., Il vantaggio di questo è il tempo di inizializzazione più veloce, ma il compromesso è che gli errori di configurazione possono essere scoperti solo dopo la richiesta del bean, che potrebbe essere diverse ore o addirittura giorni dopo che l’applicazione è già stata eseguita.

    Conclusione

    In questo articolo, abbiamo presentato i concetti di inversione del controllo e dell’iniezione di dipendenza e li abbiamo esemplificati nel framework Spring.

    Puoi leggere di più su questi concetti negli articoli di Martin Fowler:

    • Inversione dei contenitori di controllo e modello di iniezione delle dipendenze.,
    • Inversione di controllo

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *