Annotation @Autowired di Spring

La annotazione @Autowired di Spring viene utilizzata per l’iniezione automatica delle dipendenze. Il framework Spring è basato sull’iniezione delle dipendenze e iniettiamo le dipendenze di classe attraverso il file di configurazione del fagiolo di primavera.

Spring @Autowired Annotation

Di solito forniamo i dettagli di configurazione del fagiolo nel file di configurazione del fagiolo di primavera e specifichiamo anche i fagioli che verranno iniettati in altri fagioli usando l’attributo ref. Ma il framework Spring fornisce anche funzionalità di autowiring dove non è necessario fornire esplicitamente i dettagli dell’iniezione di fagioli. Ci sono modi diversi attraverso i quali possiamo autowire un fagiolo di primavera.

  1. autowire byName – Per questo tipo di autowiring, il metodo setter viene utilizzato per l’iniezione delle dipendenze. Inoltre, il nome della variabile deve essere lo stesso nella classe in cui inietteremo la dipendenza e nel file di configurazione del fagiolo di primavera.
  2. autowire byType – Per questo tipo di autowiring, viene utilizzato il tipo di classe. Quindi dovrebbe esserci solo un bean configurato per questo tipo nel file di configurazione del bean Spring.
  3. autowire by constructor – Questo è quasi simile all’autowire byType, l’unica differenza è che viene utilizzato il costruttore per iniettare la dipendenza.
  4. autowire by autodetect – Se si è su Spring 3.0 o versioni precedenti, questa è una delle opzioni di autowire disponibili. Questa opzione veniva utilizzata per autowire by constructor o byType, come determinato dal contenitore Spring. Dato che abbiamo già così tante opzioni, questa opzione è deprecata. Non tratterò questa opzione in questo tutorial.
  5. @Autowired annotation – Possiamo utilizzare l’annotazione Spring @Autowired per l’autowiring di bean Spring. @Autowired l’annotazione può essere applicata alle variabili e ai metodi per l’autowiring byType. Possiamo anche utilizzare @Autowired annotazione sul costruttore per l’autowiring basato sul costruttore di Spring. Per far sì che @Autowired l’annotazione funzioni, è necessario abilitare la configurazione basata su annotazioni nel file di configurazione del bean Spring. Ciò può essere fatto mediante l’elemento context:annotation-config o definendo un bean di tipo org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.
  6. La notazione @Qualifier – Questa annotazione viene utilizzata per evitare conflitti nella mappatura dei bean e dobbiamo fornire il nome del bean che verrà utilizzato per l’autowiring. In questo modo possiamo evitare problemi in cui vengono definiti più bean dello stesso tipo. Questa annotazione di solito funziona con l’annotazione @Autowired. Per i costruttori con argomenti multipli, possiamo utilizzare questa annotazione con i nomi degli argomenti nel metodo.

Per impostazione predefinita, l’autowiring dei bean Spring è disattivato. Il valore predefinito dell’autowire dei bean Spring è “default”, il che significa che non verrà eseguito alcun autowiring. Anche il valore “no” dell’autowire ha lo stesso comportamento. Per mostrare l’uso dell’autowiring dei bean Spring, creiamo un semplice progetto Spring Maven. Il nostro progetto finale avrà un aspetto simile all’immagine sottostante. Esaminiamo ciascuna delle opzioni di autowire una per una. Per fare ciò, creeremo un bean Model e una classe di servizio dove inietteremo il bean del modello.

Spring @Autowired Annotation – Dipendenze Maven

Per l’autowiring di Spring, non è necessario aggiungere ulteriori dipendenze. Il nostro file pom.xml ha dipendenze core del framework Spring e ha un aspetto simile al seguente.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>SpringBeanAutowiring</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.2.RELEASE</spring-framework.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>

	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>
</project>

Primavera@Autowired Annotazione – Modello Bean

Creiamo un semplice Java Bean chiamato Employee. Questo bean avrà una singola proprietà con metodi getter e setter. Inizializzeremo il valore di questa proprietà nel file di configurazione del bean di primavera.

package com.journaldev.spring.autowiring.model;

public class Employee {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Primavera@Autowired Annotazione – Classe di Servizio

Creiamo la nostra classe di servizio in cui inietteremo il bean Employee tramite l’autowiring di primavera.

package com.journaldev.spring.autowiring.service;

import com.journaldev.spring.autowiring.model.Employee;

public class EmployeeService {

	private Employee employee;

	// il costruttore è utilizzato per l'autowire tramite costruttore
	public EmployeeService(Employee emp) {
		System.out.println("Autowiring by constructor used");
		this.employee = emp;
	}

	// costruttore predefinito per evitare BeanInstantiationException per l'autowire
	// byName o byType
	public EmployeeService() {
		System.out.println("Default Constructor used");
	}

	// utilizzato per l'autowire byName e byType
	public void setEmployee(Employee emp) {
		this.employee = emp;
	}

	public Employee getEmployee() {
		return this.employee;
	}
}

Utilizzeremo la stessa classe di servizio per eseguire l’autowiring di Spring tramite byName, byType e by constructor. Il metodo setter verrà utilizzato per l’autowiring di Spring tramite byName e byType, mentre l’iniezione basata sul costruttore verrà utilizzata tramite l’attributo di autowire del costruttore. Quando utilizziamo l’autowire di Spring tramite byName o byType, viene utilizzato il costruttore predefinito. Ecco perché abbiamo definito esplicitamente il costruttore predefinito per il bean EmployeeService.

Spring @Autowired Annotation – Esempio di autowiring byType

Creiamo una classe separata con l’annotazione @Autowired di Spring per l’autowiring byType.

package com.journaldev.spring.autowiring.service;

import org.springframework.beans.factory.annotation.Autowired;

import com.journaldev.spring.autowiring.model.Employee;

public class EmployeeAutowiredByTypeService {

	//L'annotazione Autowired sulla variabile/setter è equivalente a autowire="byType"
	@Autowired
	private Employee employee;
	
	@Autowired
	public void setEmployee(Employee emp){
		this.employee=emp;
	}
	
	public Employee getEmployee(){
		return this.employee;
	}
}

Nota che ho annotato sia la variabile Employee che il relativo metodo setter con l’annotazione @Autowired di Spring, tuttavia solo uno di questi è sufficiente per l’autowiring del bean di Spring.

Annotation @Autowired di primavera e autowiring di Bean tramite esempio di costruttore

Creiamo un’altra classe di servizio dove utilizzeremo l’annotazione @Autowired per l’iniezione basata sul costruttore. Vedremo anche l’utilizzo dell’annotazione @Qualifier.

package com.journaldev.spring.autowiring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.journaldev.spring.autowiring.model.Employee;

public class EmployeeAutowiredByConstructorService {

	private Employee employee;

	// L'annotazione Autowired sul costruttore è equivalente a autowire="constructor"
	@Autowired(required=false)
	public EmployeeAutowiredByConstructorService(@Qualifier("employee") Employee emp){
		this.employee=emp;
	}
	
	public Employee getEmployee() {
		return this.employee;
	}
}

Quando questo bean sarà inizializzato dal framework Spring, verrà utilizzato il bean con nome “employee” per l’autowiring. L’annotazione @Autowired di Spring accetta un argomento “required” che è un booleano con valore predefinito TRUE. Possiamo definirlo come “false” in modo che il framework Spring non lanci alcuna eccezione se non viene trovato alcun bean adatto per l’autowiring.

Primavera @Autowired Annotation – File di Configurazione del Bean

Il file di configurazione del bean di Spring è la parte principale di qualsiasi applicazione Spring. Vediamo come appare il nostro file di configurazione del bean di Spring e poi esamineremo ogni parte.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.0.xsd"
		
		default-autowire="byName" default-autowire-candidates="*" >

<bean name="employee" class="com.journaldev.spring.autowiring.model.Employee">
	<property name="name" value="Pankaj"></property>
</bean>

<bean name="employee1" class="com.journaldev.spring.autowiring.model.Employee" autowire-candidate="false">
	<property name="name" value="Dummy Name"></property>
</bean>

<!-- autowiring byName, bean name should be same as the property name -->
<bean name="employeeServiceByName" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byName" />

<!-- autowiring byType, there should be only one bean definition for the mapping -->
<bean name="employeeServiceByType" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byType" />

<!-- autowiring by constructor -->
<bean name="employeeServiceConstructor" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="constructor" />

<!-- Enable Annotation based configuration -->
<context:annotation-config />

<!-- using @Autowiring annotation in below beans, byType and constructor -->
<bean name="employeeAutowiredByTypeService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService" />
</beans>

Punti importanti riguardo al file di configurazione del bean di Spring sono:

  • beans elemento default-autowire viene utilizzato per definire il metodo di autowiring predefinito. Qui sto definendo il metodo di autowiring predefinito come byName.
  • beans elemento default-autowire-candidates serve per fornire il pattern per i nomi dei bean che possono essere utilizzati per l’autowiring. Per semplicità, sto consentendo che tutte le definizioni dei bean siano idonee per l’autowiring, tuttavia possiamo definire un certo pattern per l’autowiring. Ad esempio, se vogliamo solo definizioni di bean DAO per l’autowiring, possiamo specificarlo come default-autowire-candidates="*DAO".
  • autowire-candidate="false" viene utilizzato in una definizione di bean per renderlo non idoneo per l’autowiring. È utile quando abbiamo molteplici definizioni di bean per un singolo tipo e vogliamo che alcune di esse non vengano autowired. Ad esempio, nelle configurazioni dei bean di Spring di cui sopra, il bean “employee1” non verrà utilizzato per l’autowiring.
  • L’attributo autowire byName, byType e constructor è autoesplicativo, nulla di più da spiegare.
  • context:annotation-config viene utilizzato per abilitare il supporto alla configurazione basata su annotazioni. Nota che i bean employeeAutowiredByTypeService e employeeAutowiredByConstructorService non hanno attributi autowire.

Spring @Autowired Annotation – Test Program

Ora che la nostra applicazione Spring è pronta con tutti i tipi di autowiring di Spring, scriviamo un semplice programma di test per verificare se funziona come previsto o meno.

package com.journaldev.spring.autowiring.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService;
import com.journaldev.spring.autowiring.service.EmployeeService;

public class SpringMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
		
		EmployeeService serviceByName = ctx.getBean("employeeServiceByName", EmployeeService.class);
		
		System.out.println("Autowiring byName. Employee Name="+serviceByName.getEmployee().getName());
		
		EmployeeService serviceByType = ctx.getBean("employeeServiceByType", EmployeeService.class);
		
		System.out.println("Autowiring byType. Employee Name="+serviceByType.getEmployee().getName());
		
		EmployeeService serviceByConstructor = ctx.getBean("employeeServiceConstructor", EmployeeService.class);
		
		System.out.println("Autowiring by Constructor. Employee Name="+serviceByConstructor.getEmployee().getName());
		
		// stampa dell'hashcode per confermare che tutti gli oggetti sono di tipo diverso
		System.out.println(serviceByName.hashCode()+"::"+serviceByType.hashCode()+"::"+serviceByConstructor.hashCode());
		
		// Testing delle annotazioni @Autowired
		EmployeeAutowiredByTypeService autowiredByTypeService = ctx.getBean("employeeAutowiredByTypeService",EmployeeAutowiredByTypeService.class);
		
		System.out.println("@Autowired byType. Employee Name="+autowiredByTypeService.getEmployee().getName());

		EmployeeAutowiredByConstructorService autowiredByConstructorService = ctx.getBean("employeeAutowiredByConstructorService",EmployeeAutowiredByConstructorService.class);
		
		System.out.println("@Autowired by Constructor. Employee Name="+autowiredByConstructorService.getEmployee().getName());

		ctx.close();
	}
}

Il programma è semplice, stiamo solo creando il contesto dell’applicazione Spring e lo usiamo per ottenere diversi bean e stampare il nome dell’impiegato. Quando eseguiamo l’applicazione sopra, otteniamo l’output seguente.

Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Mar 31, 2014 10:41:58 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Default Constructor used
Default Constructor used
Autowiring by constructor used
Autowiring byName. Employee Name=Pankaj
Autowiring byType. Employee Name=Pankaj
Autowiring by Constructor. Employee Name=Pankaj
21594592::15571401::1863015320
@Autowired byType. Employee Name=Pankaj
@Autowired by Constructor. Employee Name=Pankaj
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy

Come puoi vedere, per l’autowire byName e byType, il costruttore predefinito senza argomenti viene utilizzato per inizializzare il bean. Per l’autowire by constructor, viene utilizzato il costruttore basato su parametri. Dall’hashcode di tutte le variabili, abbiamo confermato che tutti i beans di Spring sono oggetti differenti e non si riferiscono allo stesso oggetto. Dato che abbiamo rimosso “employee1” dalla lista dei beans idonei per l’autowiring, non c’è stata confusione nella mappatura del bean. Se rimuoviamo autowire-candidate="false" dalla definizione di “employee1”, otterremo il seguente messaggio di errore durante l’esecuzione del metodo principale sopra indicato.

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeServiceByType' defined in class path resource [spring.xml]: Unsatisfied dependency expressed through bean property 'employee': : No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1278)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1170)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
	at com.journaldev.spring.autowiring.main.SpringMain.main(SpringMain.java:12)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1263)
	... 13 more

Questo è tutto per l’annotazione Spring @Autowired e la funzione di autowiring di Spring; per ulteriori dettagli, scarica il progetto di esempio dal link sottostante e analizzalo.

Scarica il progetto di autowiring di Spring Bean

Source:
https://www.digitalocean.com/community/tutorials/spring-autowired-annotation