Annotazione Spring @Qualifier

1. Panoramica

In questo articolo, esploreremo cosa può aiutarci l' annotazione @Qualifier , quali problemi risolve e come usarla.

Spiegheremo anche come è diverso dall'annotazione @Primary e dall'autowiring per nome.

2. Autowire Necessità di disambiguazione

L' annotazione @Autowired è un ottimo modo per rendere esplicita la necessità di iniettare una dipendenza in Spring. E sebbene sia utile, ci sono casi d'uso per i quali questa annotazione da sola non è sufficiente a Spring per capire quale bean iniettare.

Per impostazione predefinita, Spring risolve le voci cablate automaticamente per tipo.

Se più di un bean dello stesso tipo è disponibile nel contenitore, il framework lancerà NoUniqueBeanDefinitionException , indicando che più di un bean è disponibile per il cablaggio automatico.

Immaginiamo una situazione in cui esistono due possibili candidati per Spring da iniettare come collaboratori di fagioli in una determinata istanza:

@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } } @Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } } @Component public class FooService { @Autowired private Formatter formatter; }

Se proviamo a caricare FooService nel nostro contesto, il framework Spring genererà un'eccezione NoUniqueBeanDefinitionException . Questo perché Spring non sa quale fagiolo iniettare . Per evitare questo problema, esistono diverse soluzioni. L' annotazione @Qualifier è una di queste.

3. Annotazione @Qualifier

Usando l' annotazione @Qualifier , possiamo eliminare il problema di quale bean debba essere iniettato .

Rivediamo il nostro esempio precedente e vediamo come risolviamo il problema includendo l' annotazione @Qualifier per indicare quale bean vogliamo utilizzare:

public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }

Includendo l' annotazione @Qualifier insieme al nome della specifica implementazione che vogliamo usare - in questo esempio, Foo - possiamo evitare ambiguità quando Spring trova più bean dello stesso tipo.

Dobbiamo tenere in considerazione che il nome del qualificatore da utilizzare è quello dichiarato nell'annotazione @Component .

Si noti che avremmo potuto utilizzare anche l' annotazione @Qualifier sulle classi di implementazione del Formatter , invece di specificare i nomi nelle loro annotazioni @Component , per ottenere lo stesso effetto:

@Component @Qualifier("fooFormatter") public class FooFormatter implements Formatter { //... } @Component @Qualifier("barFormatter") public class BarFormatter implements Formatter { //... } 

4. @Qualifier vs @Primary

C'è un'altra annotazione chiamata @Primary che possiamo usare per decidere quale bean iniettare quando è presente ambiguità riguardo l' inserimento di dipendenze.

Questa annotazione definisce una preferenza quando sono presenti più bean dello stesso tipo . Il bean associato all'annotazione @Primary verrà utilizzato se non diversamente indicato.

Vediamo un esempio:

@Configuration public class Config { @Bean public Employee johnEmployee() { return new Employee("John"); } @Bean @Primary public Employee tonyEmployee() { return new Employee("Tony"); } }

In questo esempio, entrambi i metodi restituiscono lo stesso tipo Employee . Il bean che Spring inietterà è quello restituito dal metodo tonyEmployee . Questo perché contiene l' annotazione @Primary . Questa annotazione è utile quando vogliamo specificare quale bean di un certo tipo deve essere iniettato per impostazione predefinita .

E nel caso in cui avessimo bisogno dell'altro fagiolo in un punto di iniezione, avremmo bisogno di indicarlo specificamente. Possiamo farlo tramite l' annotazione @Qualifier . Ad esempio, potremmo specificare che vogliamo utilizzare il bean restituito dal metodo johnEmployee utilizzando l' annotazione @Qualifier .

Vale la pena notare che se sono presenti entrambe le annotazioni @Qualifier e @Primary , l' annotazione @Qualifier avrà la precedenza. Fondamentalmente, @Primary definisce un valore predefinito, mentre @Qualifier è molto specifico.

Vediamo un altro modo di utilizzare l' annotazione @Primary , questa volta utilizzando l'esempio iniziale:

@Component @Primary public class FooFormatter implements Formatter { //... } @Component public class BarFormatter implements Formatter { //... } 

In questo caso, l' annotazione @Primary viene inserita in una delle classi di implementazione e disambigua lo scenario.

5. @Qualifier vs Autowiring by Name

Un altro modo per decidere tra più bean durante l'autowiring è utilizzare il nome del campo da iniettare. Questa è l'impostazione predefinita nel caso in cui non ci siano altri suggerimenti per la primavera . Vediamo del codice basato sul nostro esempio iniziale:

public class FooService { @Autowired private Formatter fooFormatter; }

In questo caso, Spring determinerà che il bean da iniettare è FooFormatter poiché il nome del campo è abbinato al valore che abbiamo usato nell'annotazione @Component per quel bean.

6. Conclusione

Abbiamo descritto gli scenari in cui dobbiamo chiarire quali fagioli iniettare. In particolare, abbiamo descritto l' annotazione @Qualifier e l'abbiamo confrontata con altri modi simili per determinare quali bean devono essere utilizzati.

Come al solito, il codice completo di questo articolo è disponibile su GitHub.