Now that we have a good understanding of how to create beans and make sure they get into the the Application Context, let’s have a look at defining relations between these beans
We talked about this in a general way when we first introduced DI. Let’s make that more concrete and see how we can set up a dependency between two beans.
The container injects the dependencies for us, but we have to define those dependencies.
There are primarily three ways to define or inject dependencies:
- constructor injection
- setter injection
- field injection
Constructor-Based DI
In constructor-based injection we inject dependencies in a class via its constructor arguments. Each constructor argument represents a dependency.
Spring will inject those dependencies in our class automatically.
Let’s take our ProjectServiceImpl class as an example and inject IProjectRepository in this class via a constructor argument:
@Service
public class ProjectServiceImpl implements IProjectService {
private IProjectRepository projectRepository;
public ProjectServiceImpl(IProjectRepository projectRepository) {
this.projectRepository = projectRepository;
}
// ...
}
he Spring container will fetch the projectRepository bean for us and inject it in our service class.
Note that since we have a single constructor, the @Autowired annotation is optional.
If we define more than one constructor and we want one of them to inject dependencies on creating the bean, then we need to add @Autowired on the required constructor.
Overall, constructor based dependency injection is clean and doesn’t introduce any container specific classes, annotations or other dependencies.
Setter-Based DI
In setter-based injection, we inject dependencies using the setter methods of the required dependencies declared as fields.
Let’s create a new service class implementation that will inject the repository dependency using setter injection:
public class ProjectServiceImplSetterInjection implements IProjectService {
private IProjectRepository projectRepository;
@Autowired
public void setProjectRepository(IProjectRepository projectRepository) {
this.projectRepository = projectRepository;
}
// ...
}
The setProjectRepository setter will be used to inject the appropriate projectRepository bean in our class using the @Autowired annotation added to the setter.
Next, let’s define the service in our configuration class AppConfig:
@Configuration
public class LsAppConfig {
@Bean
public IProjectService projectServiceImplSetterInjection() {
return new ProjectServiceImplSetterInjection();
}
}
The container will inject the projectRepository dependency after calling the service constructor.
Field-Based DI
In field-based dependency injection we inject dependencies using the @Autowired annotation directly on fields.
Let’s create a new service class implementation that will inject the repository dependency using @Autowired:
@Service
public class ProjectServiceImplAutowiring implements IProjectService {
@Autowired
private IProjectRepository projectRepository;
// ...
}
This is all we need to do. The Spring container will fetch the appropriate bean projectRepository and inject it in our service class.
The default way @Autowired works is it matches the bean by-type, i.e. it will fetch the bean of type IProjectRepository and inject it in our class.
Next, we’ll see what happens if we’re trying to inject a bean by interface and we have multiple candidate beans that implement that interface.