Constructor Injection in primavera con Lombok

1. Introduzione

Lombok è una libreria estremamente utile che supera il codice boilerplate. Se non lo conosci ancora, consiglio vivamente di dare un'occhiata al tutorial precedente - Introduzione a Project Lombok.

In questo articolo, dimostreremo la sua usabilità se combinato con l' inserimento delle dipendenze basato sul costruttore di Spring .

2. Iniezione delle dipendenze basata sul costruttore

Un buon modo per collegare le dipendenze in Spring usando l' inserimento delle dipendenze basato su istruttore . Questo approccio ci obbliga a passare esplicitamente le dipendenze del componente a un costruttore.

Diversamente dall'iniezione delle dipendenze basata sul campo , offre anche una serie di vantaggi:

  • non è necessario creare un componente di configurazione specifico del test: le dipendenze vengono iniettate esplicitamente in un costruttore
  • progettazione coerente: tutte le dipendenze richieste sono enfatizzate e gestite dalla definizione del costruttore
  • semplici unit test - ridotto l'overhead di Spring Framework
  • rivendicata la libertà di utilizzare le parole chiave finali

Tuttavia, a causa della necessità di scrivere un costruttore, porta a una base di codice significativamente più grande. Considera i due esempi di GreetingService e FarewellService:

@Component public class GreetingService { @Autowired private Translator translator; public String produce() { return translator.translate("hello"); } }
@Component public class FarewellService { private final Translator translator; public FarewellService(Translator translator) { this.translator = translator; } public String produce() { return translator.translate("bye"); } }

Fondamentalmente, entrambi i componenti fanno la stessa cosa: chiamano un traduttore configurabile con una parola specifica per l'attività.

La seconda variazione, tuttavia, è molto più offuscata a causa del boilerplate del costruttore che in realtà non apporta alcun valore al codice.

Nella versione più recente della primavera, il suo costruttore non ha bisogno di essere annotato con l' annotazione @Autowired .

3. Iniezione del costruttore con Lombok

Con Lombok , è possibile generare un costruttore per tutti i campi della classe (con @AllArgsConstructor ) o per tutti i campi della classe finale (con @RequiredArgsConstructor ). Inoltre, se hai ancora bisogno di un costruttore vuoto, puoi aggiungere un'ulteriore annotazione @NoArgsConstructor .

Creiamo un terzo componente, analogo ai due precedenti:

@Component @RequiredArgsConstructor public class ThankingService { private final Translator translator; public String produce() { return translator.translate("thank you"); } }

L'annotazione sopra farà sì che Lombok generi un costruttore per noi:

@Component public class ThankingService { private final Translator translator; public String thank() { return translator.translate("thank you"); } /* Generated by Lombok */ public ThankingService(Translator translator) { this.translator = translator; } }

4. Costruttori multipli

Un costruttore non deve essere annotato fintanto che ce n'è solo uno in un componente e Spring può sceglierlo senza ambiguità come quello giusto per istanziare un nuovo oggetto. Una volta che ce ne sono altri, è necessario annotare anche quello che deve essere utilizzato dal contenitore IoC.

Considera l' esempio di ApologizeService :

@Component @RequiredArgsConstructor public class ApologizeService { private final Translator translator; private final String message; @Autowired public ApologizeService(Translator translator) { this(translator, "sorry"); } public String produce() { return translator.translate(message); } }

Il componente di cui sopra è opzionalmente configurabile con il campo messaggio che non può cambiare dopo la creazione del componente (da qui la mancanza di un setter ). Quindi ci ha richiesto di fornire due costruttori: uno con la configurazione completa e l'altro con un valore predefinito implicito del messaggio .

A meno che uno dei costruttori non sia annotato con @Autowired , @Inject o @Resource , Spring genererà un errore:

Failed to instantiate [...]: No default constructor found;

Se volessimo annotare il costruttore generato da Lombok , dovremmo passare l'annotazione con un parametro onConstructor di @AllArgsConstructor :

@Component @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ApologizeService { // ... }

Il parametro onConstructor accetta un array di annotazioni (o una singola annotazione come in questo esempio specifico) che devono essere inserite in un costruttore generato. L'idioma del doppio trattino basso è stato introdotto a causa dei problemi di compatibilità con le versioni precedenti. Secondo la documentazione:

La ragione della strana sintassi è far funzionare questa caratteristica nei compilatori javac 7; il @__tipo è un riferimento di annotazione al tipo di annotazione __(doppio trattino basso) che in realtà non esiste; questo fa sì che javac 7 ritardi l'interruzione del processo di compilazione a causa di un errore perché è possibile che un processore di annotazioni crei successivamente il __tipo.

5. Riepilogo

In questo tutorial, abbiamo dimostrato che non è necessario privilegiare DI basato sul campo rispetto a DI basato su costruttore in termini di codice boilerplate aumentato.

Grazie a Lombok, è possibile automatizzare la generazione di codice comune senza un impatto sulle prestazioni in fase di esecuzione, abbreviando il codice lungo e oscuro per l'uso di un'annotazione su una sola riga.

Il codice utilizzato durante il tutorial è disponibile su GitHub.