When to use constructor injection in Spring? [duplicate]
Asked Answered
S

1

10

When to use constructor injection in Spring?

I heard that constructor injection is particularly useful when you absolutely must have an instance of the dependency class before your component is used. But what does it mean?

Can anybody explain me with some simple examples the following moments:

  • What are the benefits that I will get using constructor injection?
  • What is dynamic constructor injection?
Sharlenesharline answered 25/11, 2014 at 16:52 Comment(1)
Injecting in constructors allows you to have final dependency as well.Polynices
C
17

The correct approach is to use constructor injection whenever it's possible. Thanks to that it's clear what are the object dependencies and you are not able to create one if you do not provide all that are required.

Use constructor injection as below.

public class ProjectService {
    private final ProjectRepository projectRepository;
    private final TaskRepository taskRepository;

    public ProjectService(TaskRepository taskService, ProjectRepository projectService) {
        Assert.notNull(taskService);
        Assert.notNull(projectService);

        this.taskRepository = taskService;
        this.projectRepository = projectService;
    }

    public Project load(Long projectId) {
        return projectRepository.findById(projectId);
    }
}
  • final fields make sure that dependencies are not changed after object is initialized
  • Assert.notNull makes sure that you don't put null values instead of real objects.

When you use setter injection or field injection your API lets you create object in incorrect state. Consider an example:

public class ProjectService {
    private ProjectRepository projectRepository;
    private TaskRepository taskRepository;

    public Project load(Long projectId) {
        return projectRepository.findById(projectId);
    }

    @Autowired
    public void setProjectRepository(ProjectRepository projectRepository) {
        this.projectRepository = projectRepository;
    }

    @Autowired
    public void setTaskRepository(TaskRepository taskRepository) {
        this.taskRepository = taskRepository;
    }
}
ProjectService projectService = new ProjectService();
projectService.load(1L); // NullPointerException is thrown

For all not optional dependencies you can use setter injection. Read more on Oliver Gierke (Spring Data lead) blog: http://olivergierke.de/2013/11/why-field-injection-is-evil/

Update 15.01.2019

Starting from Spring 4.3 there is no need to put @Autowired annotation on the constructor if only single constructor is present.

Consol answered 25/11, 2014 at 17:8 Comment(5)
While I agree on the usefulness of final fields, the Assert.notNull can be done in a setter as easily. The API example can only happen if someone is silly enough to try to construct a bean by hand. Which should not be possible anyway.Consonantal
Indeed, Assert.notNull can be done in setters as well - I posted full example of how I believe Java class should look like regarding construction. If your class is public and you want to build good API, you should be aware that it can be also used outside of Spring context - the trivial example is unit test.Consol
Any decent unit test framework can construct beans with mock dependencies. If your bean is supposed to work in any context then the best option is a factory, not explicit construction.Consonantal
One of the principles of object oriented programming is making sure that your objects are always in proper state. With constructor injection you explicitly show required dependencies that make you object actually work. It's a good practice that let you avoid NPE and confusion in the future.Consol
I agree with this answer, additionally you can check this article that helped me a lot spring.io/blog/2007/07/11/…Addlepated

© 2022 - 2024 — McMap. All rights reserved.