Guida alla primavera @Autowired

1. Panoramica

A partire da Spring 2.5, il framework ha introdotto l'inserimento delle dipendenze basato sulle annotazioni . L'annotazione principale di questa funzione è @Autowired . Consente a Spring di risolvere e iniettare i bean che collaborano nel nostro bean.

In questo tutorial, daremo prima un'occhiata a come abilitare il cablaggio automatico e il filevarimodi per autowire i fagioli. Successivamente, parleremo della risoluzione dei conflitti tra i bean utilizzando l' annotazione @Qualifier , oltre a potenziali scenari di eccezione.

2. Abilitazione delle annotazioni @Autowired

Il framework Spring consente l'inserimento automatico delle dipendenze. In altre parole, dichiarando tutte le dipendenze dei bean in un file di configurazione Spring, il contenitore Spring può autowire le relazioni tra i bean che collaborano . Questo si chiama autowiring Spring bean .

Per utilizzare la configurazione basata su Java nella nostra applicazione, abilitiamo l'iniezione guidata dall'annotazioneper caricare la nostra configurazione Spring:

@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}

In alternativa, il file l'annotazione viene utilizzata principalmente per attivare le annotazioni di inserimento delle dipendenze nei file XML Spring.

Inoltre, Spring Boot introduce l' annotazione @SpringBootApplication . Questa singola annotazione è equivalente all'uso di @Configuration , @EnableAutoConfiguration e @ComponentScan .

Usiamo questa annotazione nella classe principale dell'applicazione:

@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }

Di conseguenza, quando eseguiamo questa applicazione Spring Boot, scansionerà automaticamente i componenti nel pacchetto corrente e nei suoi sotto-pacchetti . Quindi li registrerà nel contesto dell'applicazione di Spring e ci consentirà di iniettare i bean usando @Autowired .

3. Utilizzo di @Autowired

Dopo aver abilitato l' inserimento di annotazioni, possiamo usare il cablaggio automatico su proprietà, setter e costruttori .

3.1. @Autowired su Proprietà

Vediamo come possiamo annotare una proprietà usando @Autowired . Ciò elimina la necessità di getter e setter.

Per prima cosa, definiamo un bean fooFormatter :

@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }

Poi, ci iniettiamo questo fagiolo nella FooService bean utilizzando @Autowired sulla definizione di campo:

@Component public class FooService { @Autowired private FooFormatter fooFormatter; }

Di conseguenza, Spring inietta fooFormatter quando viene creato FooService .

3.2. @Autowired su Setters

Ora proviamo ad aggiungere l' annotazione @Autowired su un metodo setter.

Nell'esempio seguente, il metodo setter viene chiamato con l'istanza di FooFormatter quando viene creato FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } } 

3.3. @Autowired on Constructors

Infine, usiamo @Autowired su un costruttore.

Vedremo che un'istanza di FooFormatter viene iniettata da Spring come argomento per il costruttore FooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }

4. @ Dipendenze cablate e facoltative

Quando viene costruito un bean, dovrebbero essere disponibili le dipendenze @Autowired . Altrimenti, se Spring non è in grado di risolvere un bean per il cablaggio, genererà un'eccezione .

Di conseguenza, impedisce al contenitore Spring di avviarsi correttamente con l'eccezione del modulo:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Per risolvere questo problema, dobbiamo dichiarare un bean del tipo richiesto:

public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }

5. Disambiguazione Autowire

Per impostazione predefinita, Spring risolve le voci @Autowired per tipo. Se nel contenitore è disponibile più di un bean dello stesso tipo, il framework genererà un'eccezione irreversibile .

Per risolvere questo conflitto, dobbiamo dire a Spring esplicitamente quale bean vogliamo iniettare.

5.1. Autowiring da @Qualifier

Ad esempio, vediamo come possiamo utilizzare l' annotazione @Qualifier per indicare il bean richiesto.

Innanzitutto, definiremo 2 bean di tipo Formatter :

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

Ora proviamo a iniettare un bean Formatter nella classe FooService :

public class FooService { @Autowired private Formatter formatter; }

In our example, there are two concrete implementations of Formatter available for the Spring container. As a result, Spring will throw a NoUniqueBeanDefinitionException exception when constructing the FooService:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter 

We can avoid this by narrowing the implementation using a @Qualifier annotation:

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

When there are multiple beans of the same type, it's a good idea to use @Qualifier to avoid ambiguity.

Please note that the value of the @Qualifier annotation matches with the name declared in the @Component annotation of our FooFormatter implementation.

5.2. Autowiring by Custom Qualifier

Spring also allows us to create our own custom @Qualifier annotation. To do so, we should provide the @Qualifier annotation with the definition:

@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }

Then we can use the FormatterType within various implementations to specify a custom value:

@FormatterType("Foo") @Component public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@FormatterType("Bar") @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Finally, our custom Qualifier annotation is ready to use for autowiring:

@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; } 

The value specified in the @Target meta-annotation restricts where to apply the qualifier, which in our example is fields, methods, types, and parameters.

5.3. Autowiring by Name

Spring uses the bean's name as a default qualifier value. It will inspect the container and look for a bean with the exact name as the property to autowire it.

Hence, in our example, Spring matches the fooFormatter property name to the FooFormatter implementation. Therefore, it injects that specific implementation when constructing FooService:

public class FooService { @Autowired private Formatter fooFormatter; }

6. Conclusion

In this article, we discussed autowiring and the different ways to use it. We also examined ways to solve two common autowiring exceptions caused by either a missing bean or an ambiguous bean injection.

The source code of this article is available on the GitHub project.