Tutorial on Spring @Autowired

0
119

@Autowired is one of the key annotation in annotation based Dependency Injection. Since version 2.5, Spring provides the @Autowired annotation to discover the beans automatically and inject collaborating beans (other associated dependent beans) into our bean.

In this guide we will look into enabling auto-wiring and various ways of autowiring beans using @Autowired annotation.

1. Enable configuration to use @Autowired

By declaring all the beans in Spring Configuration file, Spring container can autowire relationships between collaborating beans. Following are the various configuration styles can be used to use @Autowired in Spring applications and you can use mixed configurations within same application.

1.1. Using Spring XML

<context:annotation-config /> is used in XML config files to enable annotation based dependency Injection.

Sample Configuration file :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.javabydeveloper.spring.autowire" />
   
</beans>

1.2. Using Java Configuration

Following is the sample java based configuration to use @Autowired to inject dependencies with in com.javabydeveloper.spring.autowire package.

@Configuration
@ComponentScan("com.javabydeveloper.spring.autowire")
public class ApplConfigForAutowired {

}

1.3. @Autowired in Spring Boot

In a Spring Boot application, auto-wiring is enabled by default. Following is sample code. @SpringBootApplication automatically loads all configuration files and scans the components in the current package and its sub-packages.

@SpringBootApplication
public class SpringBootAutowiredDemoApp {

	public static void main(String[] args) {
		// code
	}
}

2. Using @Autowired

After enabling annotation based injection, now let’s look into how we can use @Autowired annotation. @Autowired can be used on following injection points.

  1. Constructors
  2. Methods
  3. Fields and
  4. Parameters

and dependencies can be injected using by type OR by name OR by @Qualifier.

2.1. @Autowired on Constructors

Firstly let’s use @Autowired on constructor. we will see that SampleService injected by Spring to the constructor of AutowireDITestService.

package com.javabydeveloper.spring.autowire.service;

@Component
public class SampleService {

	public void sample() {
		System.out.println("Sample Service");
	}
}
package com.javabydeveloper.spring.autowire;

// imports

@Component
public class AutowireDITestService {
	
        // ...
	private SampleService sampleService;
	
	@Autowired
	public AutowireDITestService(SampleService sampleService) {
		this.sampleService = sampleService;
	}
	
        // ...	
}
public class ApplicationAutoWiredDemo {
 
    public static void main(String[] args) {
    	
    	ApplicationContext ctxt = new AnnotationConfigApplicationContext(AppConfigForAutowired.class);
        
        AutowireDITestService adits = ctxt.getBean(AutowireDITestService.class);
        adits.test();
       // ...  
    }
}

2.2. @Autowired on Setters and on Methods

Let’s try adding @Autowired on setter method.

In following example, the setter method is called with ExampleService instance when AutowireDITestService created.

package com.javabydeveloper.spring.autowire.service;
// imports

@Component
public class ExampleService {

	public void example() {
		System.out.println("Example Service");
	}
}
package com.javabydeveloper.spring.autowire;

// imports

@Component
public class AutowireDITestService {
        // ...
	private ExampleService exampleService;
	
	// @Autowired on setter
	@Autowired
	public void setExampleService(ExampleService exampleService) {
		this.exampleService = exampleService;
	}
        // ...	
}

We can also apply @Autowired on methods with any number of arguments.

package com.javabydeveloper.spring.autowire;

// imports

@Component
public class AutowireCustomMethodDITestService {

	private DemoService demoService;
	private ExampleService exampleService;
	private SampleService sampleService;
	
	@Autowired
	public void initialize(DemoService demoService, ExampleService exampleService, SampleService sampleService) {
		this.demoService = demoService;
		this.exampleService = exampleService;
		this.sampleService = sampleService;
	}
	// ...
}

2.3. @Autowired on Properties

We can use @Autowired on properties, so that we can avoid setters and getters for the autowired properties.

package com.javabydeveloper.spring.autowire.service;

@Component
public class DemoService {

	public void demo() {
		System.out.println("Demo Service");
	}
}
@Component
public class AutowireDITestService {

	// @Autowired on property
	@Autowired
	private DemoService demoService;

        // ...
}

2.4. @Autowired on Parameters

Since 5.0, Spring supports @Autowired annotation on individual methods and constructor parameters. But the only part of the core Spring Framework that actively supports autowired parameters is the JUnit Jupiter support in the spring-test module.

@SpringJUnitConfig(AppConfigForAutowired.class)
class AutowireParametersTest {

	private SampleService sampleService;

	// @Autowired on constructor parameters
	AutowireParametersTest(@Autowired SampleService sampleService) {
		this.sampleService = sampleService;
	}

	// @Autowired on method parameters
	@Test
	void injectServicesTest(@Autowired DemoService demoService,
			@Autowired(required = true) ExampleService exampleService) {

		demoService.demo();
		exampleService.example();
		sampleService.sample();
	}
}

3. @Autowired by Type

By default, Spring does auto-wire by type. we have a class type UserDao and it’s an implementation of IUserDao interface. Let’s try auto-wire it in service. There should be only one bean configured for implementation class type for IUserDao interface in the spring bean, Spring automatically inject by it’s type.

public interface IUserDao {
	public void result();
}
@Component
public class UserDao implements IUserDao {

	@Override
	public void result() {
		System.out.println("User Dao Implementation");
	}
}
@Component
public class AutowireByTypeTestService {

	@Autowired
	private IUserDao dao;
	
	public void printResults() {
		System.out.println("\n ------ Autowire By Type Results ------");
		dao.result();
	}
}
    	ApplicationContext ctxt = new AnnotationConfigApplicationContext(AppConfigForAutowired.class);
        
        AutowireByTypeTestService abtts = ctxt.getBean(AutowireByTypeTestService.class);
        abtts.printResults();
 ------ Autowire By Type Results ------
User Dao Implementation

4. Ambiguity in using @Autowired

By default, Spring does auto-wire by type. If spring found more than one bean of same type in Spring container, it leads to ambiguity issues and framework trows no-unique bean exceptions. To resolve ambiguity conflicts we need to tell Spring which bean need to inject by Using @Autowired by name OR by specifying bean with @Qualifier OR @Primary .

5. @Autowired by name

Let’s say we have IDao interface CustomerDao and EmployeeDao are its implementation classes. Spring will inspect the container and look for a bean with the exact name as the property to autowire it. Let’s see an example.

public interface IDao {
	public void result();
}
@Component
public class CustomerDao implements IDao {

	@Override
	public void result() {
		System.out.println("Customer Dao Implementation");
	}
}
@Component
public class EmployeeDao implements IDao {

	@Override
	public void result() {
		
		System.out.println("Employee Dao Implementation");
		
	}
}
@Component
public class AutowireByNameTestService {

	@Autowired
	private IDao employeeDao;
	
	@Autowired
	private IDao customerDao;
	
	public void printResults() {
		System.out.println("\n ------ Autowire By Name Results ------");
		employeeDao.result();
		customerDao.result();
	}
}
    	ApplicationContext ctxt = new AnnotationConfigApplicationContext(AppConfigForAutowired.class);
       
        AutowireByNameTestService abnts = ctxt.getBean(AutowireByNameTestService.class);
        abnts.printResults();
 ------ Autowire By Name Results ------
Employee Dao Implementation
Customer Dao Implementation

6. @Autowired by @Qualifier

@Qualifier is used to identify particular bean when you have several implementations of same type. Let’s see an example.

@Component
@Qualifier("contact")
public class ContactDao implements IDao {

	@Override
	public void result() {
		System.out.println("Contact Dao Implementation");
	}
}
@Component("address")
public class AddressDao implements IDao {

	@Override
	public void result() {
		System.out.println("Address Dao Implementation");
	}
}
@Component
public class AutowireByQualifierTestService {

	@Autowired
	@Qualifier("address")
	private IDao addressDao;
	
	@Autowired
	@Qualifier("contact")
	private IDao contactDao;
	
	public void printResults() {
		System.out.println("\n ------ Autowire By Qualifier Results ------");
		addressDao.result();
		contactDao.result();
	}
}
    	ApplicationContext ctxt = new AnnotationConfigApplicationContext(AppConfigForAutowired.class);
         
        AutowireByQualifierTestService abqts = ctxt.getBean(AutowireByQualifierTestService.class);
        abqts.printResults();
 ------ Autowire By Qualifier Results ------
Address Dao Implementation
Contact Dao Implementation

7. @Autowired with Optional dependencies

In few cases injecting dependency might be optional, but all the autowired dependencies should be available when a bean is being constructed, otherwise Spring throws exception. There are various ways we can make injecting dependency optional using @Autowired.

7.1. Using @Autowired(required = false)

@Autowired annotation required attribute by default value is true, it means dependency should be available while constructing the bean. We can use @Autowired(required = false) to make injecting dependency is optional by Spring.

@Component
public class OptionalDITestService {

	@Autowired(required = false)
	private ExerciseService exerciseService;
	
	// ...

	public void doStuff() {
		System.out.println("\n ------ Autowiring Optional Dependency Injection Results ------");
		if(exerciseService != null)
			exerciseService.exercise();
		// ...
	}
}

7.2. Using @Autowired with Java 8 Optional

Alternatively we can use Java 8 Optional instead of required element. Let’s see an example.

@Component
public class OptionalDITestService {

	@Autowired
	private Optional<ParadigmService> paradigmService;
	
	// ...

	public void doStuff() {
		// ...

		if(paradigmService.isPresent())
			paradigmService.get().paradigm();
               // ...
	}	
}

8. Conclusion

In this guide we have seen autowiring beans using @Autowired annotation various ways Spring and Spring Boot applications.

LEAVE A REPLY

Please enter your comment!
Please enter your name here