Когда использовать внедрение конструктора в Spring?

Когда использовать внедрение конструктора в Spring?

Я слышал, что внедрение конструктора особенно полезно, когда вам абсолютно необходимо иметь экземпляр класса зависимостей, прежде чем ваш компонент будет использоваться. Но что это значит?

Может ли кто-нибудь объяснить мне на нескольких простых примерах следующие моменты:

  • Какие преимущества я получу, используя внедрение конструктора?
  • Что такое внедрение динамического конструктора?

person XYZ    schedule 25.11.2014    source источник
comment
Внедрение в конструкторы также позволяет вам иметь конечную зависимость.   -  person sp00m    schedule 25.11.2014


Ответы (1)


Правильный подход — использовать внедрение конструктора, когда это возможно. Благодаря этому ясно, каковы зависимости объекта, и вы не сможете создать их, если не предоставите все, что требуется.

Используйте внедрение конструктора, как показано ниже.

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 поля гарантируют, что зависимости не изменятся после инициализации объекта
  • Assert.notNull гарантирует, что вы не поместите нулевые значения вместо реальных объектов.

Когда вы используете инъекцию сеттера или инъекцию поля, ваш API позволяет создавать объект в неправильном состоянии. Рассмотрим пример:

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

Для всех необязательных зависимостей вы можете использовать инъекцию сеттера. Подробнее читайте в блоге Оливера Гирке (руководитель Spring Data): http://olivergierke.de/2013/11/why-field-injection-is-evil/

Обновление от 15 января 2019 г.

Начиная с Spring 4.3 нет необходимости помещать аннотацию @Autowired в конструктор, если присутствует только один конструктор.

person Maciej Walkowiak    schedule 25.11.2014
comment
Хотя я согласен с полезностью final полей, Assert.notNull можно легко сделать в сеттере. Пример API может произойти только в том случае, если кто-то достаточно глуп, чтобы попытаться создать компонент вручную. Что в любом случае не должно быть возможным. - person Ordous; 25.11.2014
comment
Действительно, Assert.notNull можно сделать и в сеттерах - я опубликовал полный пример того, как, по моему мнению, должен выглядеть класс Java в отношении построения. Если ваш класс public и вы хотите создать хороший API, вы должны знать, что его также можно использовать вне контекста Spring — тривиальным примером является модульное тестирование. - person Maciej Walkowiak; 25.11.2014
comment
Любая приличная среда модульного тестирования может создавать bean-компоненты с фиктивными зависимостями. Если ваш bean-компонент должен работать в любом контексте, то лучшим вариантом является фабрика, а не явная конструкция. - person Ordous; 25.11.2014
comment
Один из принципов объектно-ориентированного программирования — убедиться, что ваши объекты всегда находятся в правильном состоянии. С внедрением конструктора вы явно показываете необходимые зависимости, которые заставляют ваш объект работать. Это хорошая практика, позволяющая избежать NPE и путаницы в будущем. - person Maciej Walkowiak; 25.11.2014
comment
Я согласен с этим ответом, кроме того, вы можете проверить эту статью, которая мне очень помогла spring.io/blog/2007/07/11/ - person Marios; 26.11.2014
comment
большое спасибо @MaciejWalkowiak - person XYZ; 26.11.2014