spring

Spring Autowiring Tutorial

One of the main tenets of the Spring framework is Dependency Injection (DI). The framework implements DI by using @Autowired annotations. These annotations were introduced starting with Spring 2.5. By using this annotation, one can leave a lot of configuration overheads and leave the handling of injection of beans to Spring.

1. Introduction

Dependency injection (DI) in Spring “is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method.”

@Autowired annotation accomplishes the DI feature. Through the use of XML based or Java based configurations (explained later in this article), when the Spring application context is being spun up, Spring automatically locates beans which have been marked as auto-wire candidates. The @Autowired annotation tells Spring where an injection needs to occur. These beans are then instantiated and then are available in the Spring application context to be used by other classes or components.

2. Setup Maven Project

Create a New Maven Project

  • Navigate to File menu in Eclipse or Spring Tool Suite IDE.
  • Click ‘File’ -> ‘New’ -> ‘Maven Project’.

Fig 1: Create project step 1

Under the “New Maven Project” window:

  • Select ‘Create a simple project….’ check box.
  • The remaining options can be kept as it is and simply click on ‘Next’.

Fig 2: Create project step 2

In the next window enter the following options:

  • For Group ID enter com.springautowire.
  • For Artifact ID enter springautowire.
  • The remaining options can be kept as it is (We will be working with a jar file here).
  • Click on ‘Finish’.

Fig 3: Create project step 3

A new maven project is created and is visible under Package Explorer in Eclipse

Fig 4: Final project structure

3. Project Demo

3.1 How to configure

To enable annotation-driven injection in a spring application, java based or XML based configurations can be used. For a java based configuration, injection by using AnnotationConfigApplicationContextloads the spring configuration.

AppConfig.java

@Configuration
@ComponentScan({"com.springautowire.domain"})
public class AppConfig {
//.....further code....
}

Here @ComponentScan annotation lets the spring context know which package to search for beans and instantiate for injection. If you wish to XML based configurations, it can be enabled by declaring it in Spring XML files like: context:annotation-config

3.2 Types of Autowiring

DI by Autowiring can be set in Spring by three major types:

  • By Setter Injection
  • By Constructor Injection
  • By Autowiring properties

3.2.1 Setter Injection

The @Autowired annotation can also be used on setter methods. In the below example, the annotation is used on the setter method for Person entity. So now the setter method is invoked with the instance of Person when Customer is created:

Customer.java

public class Customer {	
	
	private Person person;
	
	@Autowired
	public void setPerson(Person person) {
		this.person = person;
	}
	
	private String type;
	private boolean isActive;
	
	@Override
	public String toString() {
		StringBuilder s = new StringBuilder();
		s.append(person.getFirstName()).append(" ").append(person.getLastName()).append("\n")
				.append(person.getPhoneNum()).append("\n").append(type).append("\n").append(isActive);
		return s.toString();
	}

	public Person getPerson() {
		return person;
	}	

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public boolean isActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}

3.2.2 Constructor Injection

The @Autowired annotation can also be used on constructors. In the below example, the annotation is used on a constructor for the Customer class. So an instance of Person is injected as an argument to the constructor when Customeris created:

Customer.java

public class Customer {
	
	private Person person;
	
	@Autowired
	public Customer(Person person) {
		this.person = person;
	}
	
	private String type;
	private boolean isActive;
	
	@Override
	public String toString() {
		StringBuilder s = new StringBuilder();
		s.append(person.getFirstName()).append(" ").append(person.getLastName()).append("\n")
				.append(person.getPhoneNum()).append("\n").append(type).append("\n").append(isActive);
		return s.toString();
	}

	public Person getPerson() {
		return person;
	}	

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public boolean isActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}

3.2.3 Autowiring properties

This annotation can be directly on class member and/or properties. Thus this eliminates the need of setter or constructor injection.

Customer.java

public class Customer {
	
	@Autowired
	private Person person;
	
	private String type;
	private boolean isActive;
	
	@Override
	public String toString() {
		StringBuilder s = new StringBuilder();
		s.append(person.getFirstName()).append(" ").append(person.getLastName()).append("\n")
				.append(person.getPhoneNum()).append("\n").append(type).append("\n").append(isActive);
		return s.toString();
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public boolean isActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}
}

To check if the bean has been correctly instantiated and included in the spring application context, we can test by using the below java class.

Application.java

public class Application {
	
	public static void main(String[] args) {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
		
		Customer c = ctx.getBean(Customer.class);
		System.out.println(c.toString());
		
		((ConfigurableApplicationContext)(ctx)).close();
	}
}

This prints out the sample Customer to the system console. The spring application context ctx gets a hold of the bean via the getBean method. The class name in String format or .class can be passed as paramaters.

John Doe
773-876-8978
EComm
true

3.3 Handling Exceptions

Spring framework auto-wires spring beans by default. If multiple beans exist in the spring application context with the same name, this causes ambiguity. Spring throws a fatal exception in that case.
Let us consider two entities SalesRep and MarketingRep which extend from the Employee.

SalesRep.java

@Component("salesRep")
public class SalesRep extends Employee{ 
    public void execute() {
        System.out.println("Executing Sales Activity");
    }
}

MarketingRep.java

@Component("marketingRep")
public class MarketingRep extends Employee{ 
    public void execute() {
        System.out.println("Executing Marketing Activity");
    }
}

Now the Employee bean is auto-wired into an EmployeeService service layer class to perform business transactions

EmployeeService.java

public class EmployeeService {
    @Autowired
    private Employee employee;
    //.....further code....
}

Here we have two concrete instances of the Employee class. Thus two beans of same type are available for Spring to inject. As a result of this ambiguity, Spring will throw an NoUniqueBeanDefinitionException when the EmployeeService class is being instantiated. Exception:

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

This issue or ambiguous reference can be resolved with the use of the @Qualifier annotation.

EmployeeService.java

public class EmployeeService {
    @Autowired
    @Qualifier("salesRep")
    private Employee employee;
    //.....further code....
}

Here we explicitly pass the name of the bean to be injected to Spring. Thus Spring context is aware that it needs to inject bean of type salesRep when instantiating the EmployeeService class. This removes the confusion and the exception is resolved.
We can set the bean name of any class using the @Component annotation (as in this example). Or by using the @Bean annotation while defining the beans in the application context. Example:

AppConfig.java

@Configuration
public class AppConfig {

	@Bean
	public Customer customer() {
		Customer c = new Customer();
		c.setType("EComm");
		c.setActive(true);
		return c;
	}
	
	@Bean
	public Person person() {
		Person p = new Person();
		p.setFirstName("John");
		p.setLastName("Doe");
		p.setPhoneNum("773-876-8978");
		return p;
	}
}

4. Conclusion

In this tutorial, we discussed the concepts of DI and autowiring of beans in the Spring framework. Different types or means of autowiring were discussed. Although any type of injection can be used, for ease of use, property based injection is preferred. But that decision is left to individual developers and their project needs.The use of the @Qualifier annotation shows how to resolve ambigous bean references and make spring context aware of which beans to inject.

5. References

Please go through below links for further conceptual information.

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html

https://en.wikipedia.org/wiki/Dependency_injection

6. Download Source Code

Download
You can download the full source code of this example here: SpringAutowire

Diptayan Datta

Diptayan has a bachelors degree in Electronics and Communication Engineering. He also holds a Master degree in Information Systems. In his professional career, he has worked with several organizations in both software tester and developer roles. He is currently involved as an application developer in the Tax, Accounting and Corporate Law sector where he is working with Java, Spring, Hibernate, Selenium, JavaScript and AngularJS.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button