Spring Dependency Injection

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.

Leave a Reply

Your email address will not be published. Required fields are marked *