Constructor Dependency Injection in primavera

1. Introduzione

Probabilmente uno dei principi di sviluppo più importanti della moderna progettazione del software è la Dependency Injection (DI) che fluisce in modo del tutto naturale da un altro principio di fondamentale importanza: la modularità.

Questo articolo esplorerà un tipo specifico di tecnica DI chiamata iniezione delle dipendenze basata sul costruttore all'interno di Spring, che in poche parole significa che i componenti richiesti vengono passati in una classe al momento dell'istanziazione.

Per iniziare dobbiamo importare la dipendenza dal contesto primaverile nel nostro pom.xml :

 org.springframework spring-context 5.2.8.RELEASE 

Quindi dobbiamo impostare un file di configurazione . Questo file può essere un POJO o, se preferisci, un file XML.

2. Configurazione basata sull'annotazione

Il file di configurazione Java assomiglia più o meno a un semplice oggetto Java con alcune annotazioni aggiuntive:

@Configuration @ComponentScan("com.baeldung.constructordi") public class Config { @Bean public Engine engine() { return new Engine("v8", 5); } @Bean public Transmission transmission() { return new Transmission("sliding"); } } 

Qui stiamo usando le annotazioni per notificare al runtime Spring che questa classe è un fornitore di definizioni di bean ( annotazione @Bean ) e che è necessario eseguire una scansione del contesto per ulteriori bean nel pacchetto com.baeldung.spring . Successivamente, definiamo una classe Car :

@Component public class Car { @Autowired public Car(Engine engine, Transmission transmission) { this.engine = engine; this.transmission = transmission; } }

Spring incontrerà la nostra classe Car durante una scansione del pacchetto e inizializzerà la sua istanza chiamando il costruttore annotato @Autowired .

Le istanze di motore e trasmissione verranno ottenute chiamando i metodi annotati @Bean della classe Config . Infine, dobbiamo eseguire il bootstrap di un ApplicationContext utilizzando la nostra configurazione POJO:

ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Car car = context.getBean(Car.class);

3. Iniezione implicita del costruttore

A partire dalla Spring 4.3, le classi con un singolo costruttore possono omettere l' annotazione @Autowired . Un bel po 'di praticità e rimozione del boilerplate!

Inoltre, a partire da 4.3, l'iniezione basata sul costruttore può essere sfruttata nelle classi annotate @Configuration . E sì, se una tale classe ha un solo costruttore, anche l' annotazione @Autowired può essere omessa.

4. Configurazione basata su XML

Un altro modo per configurare il runtime Spring con l'inserimento delle dipendenze basato sul costruttore consiste nell'usare un file di configurazione XML:

Si noti che il costruttore-arg può accettare un valore letterale o un riferimento a un altro bean e che possono essere forniti un indice e un tipo espliciti facoltativi . Gli attributi di tipo e indice possono essere utilizzati per risolvere l'ambiguità (ad esempio se un costruttore accetta più argomenti dello stesso tipo).

L' attributo name potrebbe anche essere usato per la corrispondenza tra xml e variabili java, ma il tuo codice deve essere compilato con il flag di debug attivo.

Un contesto dell'applicazione Spring, in questo caso, deve essere avviato con ClassPathXmlApplicationContext :

ApplicationContext context = new ClassPathXmlApplicationContext("baeldung.xml"); Car car = context.getBean(Car.class);

5. Pro e contro

L'iniezione del costruttore presenta alcuni vantaggi rispetto all'iniezione sul campo.

Il primo vantaggio è la testabilità. Supponiamo di eseguire un test unitario di un bean Spring che utilizza l'iniezione di campo:

public class UserService { @Autowired private UserRepository userRepository; }

Durante la costruzione di un'istanza UserService , non possiamo inizializzare lo stato userRepository . L'unico modo per ottenere ciò è tramite l'API Reflection, che rompe completamente l'incapsulamento. Inoltre, il codice risultante sarà meno sicuro rispetto a una semplice chiamata al costruttore.

Inoltre, con l' iniezione di campo, non possiamo applicare invarianti a livello di classe.Quindi è possibile avere un'istanza UserService senza un userRepository inizializzato correttamente . Pertanto, possiamo riscontrare NullPointerException casuali qua e là. Inoltre, con l'iniezione nel costruttore, è più facile creare componenti immutabili.

Inoltre, l' utilizzo di costruttori per creare istanze di oggetti è più naturale dal punto di vista OOP.

D'altra parte, il principale svantaggio dell'iniezione del costruttore è la sua verbosità, specialmente quando un bean ha una manciata di dipendenze. A volte può essere una benedizione sotto mentite spoglie, poiché potremmo sforzarci di mantenere il numero di dipendenze minimo.

6. Conclusione

Questo breve tutorial ha mostrato le basi di due modi distinti per usare l' inserimento delle dipendenze basato sul costruttore usando il framework Spring.

L' implementazione completa di questo tutorial può essere trovata su GitHub.