1. Overview
In this tutorial, we'll look at the Spring's @Autowired annotation in detail.
When we use annotation-based configuration, @Autowired helps us inject a bean into the target bean. Throughout the tutorial, we'll investigate different usages of the @Autowired annotation.
2. Sample Application
Let's start with our sample components:
@Component
public class EmployeeService {
public void work(){
System.out.println("Working");
}
}
Here we have the EmployeeService component without any dependencies.
@Component
public class ManagerService {
public void manage(){
System.out.println("Managing");
}
}
Then we have the ManagerService component which also doesn't have any dependencies.
We'll also provide other components when needed in the examples.
2. Injection Points
Now, let's look at how we can use the @Autowired annotation.
2.1. Constructor Injection with @Autowired
Firstly, we can use @Autowired on a constructor of the target bean.
This is the recommended approach. Because when Spring creates a bean in this way, all dependencies of the bean will be injected with the instance creation:
@Component
public class ConstructorInjectedStoreService {
private final EmployeeService employeeService;
private final ManagerService managerService;
@Autowired
public ConstructorInjectedStoreService(EmployeeService employeeService,
ManagerService managerService) {
this.employeeService = employeeService;
this.managerService = managerService;
}
}
Here, we're creating the ConstructorInjectedStoreService bean. Also, we're declaring the EmployeeService and ManagerService instance fields. Since we're annotating the constructor with @Autowired, Spring will supply those dependencies to the target bean's constructor.
2.2. Field Injection with @Autowired
Secondly, we can annotate instance fields with @Autowired.
In contrast to the constructor injection, when a bean is created it may not have all its dependencies injected right away. Though, Spring will wire all dependencies to the target bean eventually:
@Component
public class FieldInjectedStoreService {
@Autowired
private EmployeeService employeeService;
@Autowired
private ManagerService managerService;
}
Here, we have the FieldInjectedStoreService bean. We're annotating its instance fields with the @Autowired annotation. As a result, Spring will inject related beans to these fields.
2.3. Setter Injection with @Autowired
Another approach we can use is the setter injection. In contrast to field injection, we'll annotate the setter methods with @Autowired:
@Component
public class SetterInjectedStoreService {
private EmployeeService employeeService;
private ManagerService managerService;
@Autowired
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@Autowired
public void setManagerService(ManagerService managerService) {
this.managerService = managerService;
}
}
Here, we have the SetterInjectedStoreService bean whose setter methods are annotated with @Autowired. So during the creation of SetterInjectedStoreService bean, Spring will call these setter methods with related bean instances.
2.4. Custom Method Injection with @Autowired
Similar to setter injection, we can annotate custom methods with @Autowired. As a result, Spring calls these methods with related bean instances:
@Component
public class CustomMethodInjectedStoreService {
private EmployeeService employeeService;
private ManagerService managerService;
@Autowired
public void prepare(EmployeeService employeeService, ManagerService managerService) {
this.employeeService = employeeService;
this.managerService = managerService;
}
}
Here, we've annotated the prepare() method with @Autowired.
2.5. Mixed Dependency Injection
Lastly, we can mix different injection methods:
@Component
public class MixedInjectedStoreService {
private final EmployeeService employeeService;
@Autowired
private ManagerService managerService;
@Autowired
public MixedInjectedStoreService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Here, we're using both the field injection and constructor injection approaches.
3. Optional Bean Dependencies
Next, we'll look at optional bean dependencies.
So far, all of our dependencies were required. Hence if Spring fails to find a suitable bean for the dependency, it will fail the application startup.
However, we may have optional beans, for example, the ones which are activated on a specific environment. Fortunately, the @Autowired annotation lets us define whether our bean dependencies are required or optional:
@Component
public class OptionalDependencyStoreService {
private final EmployeeService employeeService;
private final ManagerService managerService;
@Autowired(required = false)
private OrderService orderService;
@Autowired
public OptionalDependencyStoreService(EmployeeService employeeService,
ManagerService managerService) {
this.employeeService = employeeService;
this.managerService = managerService;
}
}
Here, we've annotated OrderService field with @Autowired. Note that we're setting the required attribute to false. Hence, if Spring cannot find a suitable bean for OrderService, it will continue with the application startup.
4. Without @Autowired
When using constructor injection, there is a special case. If the target bean has only one constructor, we don't need to annotate it with the @Autowired annotation:
@Component
public class WithoutAutowiredStoreService {
private final EmployeeService employeeService;
private final ManagerService managerService;
public WithoutAutowiredStoreService(EmployeeService employeeService,
ManagerService managerService) {
this.employeeService = employeeService;
this.managerService = managerService;
}
}
Here although we're using constructor injection, we aren't using @Autowired.
But note that this is only valid if we're using Spring Framework 4.3 or above.
5. Injection Multiple Beans
Next, let's look at how we can auto-wire multiple beans into the target bean.
When we have multiple implementations of an interface, we can inject all of them to the target bean. Furthermore, we can store these beans in an array, List, Set or Map instance:
public interface GoodService {
void buy();
}
Here we have the GoodService interface which has several implementations.
Let's see the target bean - GoodManager:
@Component
public class GoodManager {
@Autowired
private GoodService[] goodServicesArray;
@Autowired
private List<GoodService> goodServicesList;
@Autowired
private Set<GoodService> goodServicesSet;
@Autowired
private Map<String, GoodService> goodServicesMap;
}
Here, the GoodManager class declares its dependencies in the form of an array or a collection. As a result, Spring will inject all GoodService implementing beans to these fields. For Map type, the key is the name of the injected bean.
6. Overview
In this tutorial, we've looked at different usages of Spring's @Autowired annotation.
Check out the source code over on Github.