Как правильно внедрить множество сервисов в контроллер Spring MVC?

Я создал приложение Spring MVC с 3 типами пользователей. Я создал отдельные контроллеры для каждого из них. Теперь в каждый из них мне нужно внедрить классы обслуживания, поэтому я сделал это так:

@Controller
@RequestMapping("teacher")
public class TeacherController {

@Autowired
private StudentService studentService;

@Autowired
private GradeService gradeService;

@Autowired
private SubjectService subjectService;

@Autowired
private StudentGroupService studentGroupService;

@Autowired
private NewsService newsService;

@GetMapping("/index")
public String indexPage(Model theModel) {
    List<News> tempNewsList = newsService.getNews();

    theModel.addAttribute("theNewList", tempNewsList);

    return "teacher/index";
}

В этом коде используется внедрение поля. Как я теперь понял, это решение, которого следует избегать и заменять внедрением конструктора. Итак, я Autowired конструктор со всеми этими полями, как это:

@Autowired
public TeacherController(StudentService studentService, GradeService gradeService, SubjectService subjectService, StudentGroupService studentGroupService, NewsService newsService) {
    this.studentService = studentService;
    this.gradeService = gradeService;
    this.subjectService = subjectService;
    this.studentGroupService = studentGroupService;
    this.newsService = newsService;
}

Это хорошее решение - создать такой многословный конструктор в таком простом коде? А что, если бы в моем коде было еще больше сервисов? Это вообще приемлемо, или в этом случае я должен реорганизовать свой код, например делегировать службы другим службам или создать больше контроллеров?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
0
2 373
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы сами на это хорошо ответили! Spring решает именно эту проблему в документации здесь в поле под названием Конструктор или установщик DI?:

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

То есть в идеале вам следует провести рефакторинг. Использовал принципы ТВЕРДЫЙ и подумал: «Какую работу в классе я создаю?».

Спасибо за ответ. Итак, что касается решения рефакторинга, если у меня есть 3 контроллера для каждого пользователя (ученик, учитель, администратор) и много сопоставлений запросов в них, было бы лучше, например, добавить GradesController, который будет обслуживать только запросы, связанные с оценками, и принимать некоторые из функций других контроллеров?

Jarek Pie 09.01.2019 23:57

Эта идея - хорошая мысль. Это действительно зависит от того, как будет выглядеть ваш интерфейс. Вы не ограничены. Подумайте о веб-сайте учебной аудитории и о страницах, на которые могут перейти пользователи. Это может быть хорошей отправной точкой для вашего контроллера. RBAC определяет «кто» за вас. Представьте себе страницу / контроллер «оценок». Учащийся может "просматривать" его, но учитель может "редактировать". У учащегося нет доступа к функции редактирования. Вот как обычно решается эта проблема, ИМХО.

Dovmo 10.01.2019 02:30

В заключение, согласно документации, если существует много DI, вы можете оценить каждый и попытаться использовать на основе набора и / или на основе конструктора. В документации поясняется, какой из них использовать ниже:

Конструктор или установщик DI?

Поскольку вы можете смешивать DI на основе конструкторов и установщиков, рекомендуется использовать конструкторы для обязательных зависимостей и методы установки или методы конфигурации для дополнительных зависимостей. Обратите внимание, что использование аннотации @Required в методе установки может использоваться, чтобы сделать свойство обязательной зависимостью.

Команда Spring обычно выступает за внедрение конструктора, поскольку оно позволяет реализовать компоненты приложения как неизменяемые объекты и гарантирует, что требуемые зависимости не равны нулю. Более того, компоненты, внедренные конструктором, всегда возвращаются клиентскому (вызывающему) коду в полностью инициализированном состоянии. В качестве побочного примечания, большое количество аргументов конструктора является неприятным запахом кода, подразумевая, что у класса, вероятно, слишком много обязанностей, и его следует реорганизовать, чтобы лучше решить правильное разделение проблем.

Внедрение установщика должно в первую очередь использоваться только для необязательных зависимостей, которым могут быть назначены разумные значения по умолчанию внутри класса. В противном случае проверки на ненулевое значение должны выполняться везде, где код использует зависимость. Одно из преимуществ внедрения установщика состоит в том, что методы установщика делают объекты этого класса доступными для реконфигурации или повторного внедрения позже. Таким образом, управление с помощью JMX MBeans является убедительным вариантом использования для внедрения сеттера.

Используйте стиль DI, наиболее подходящий для конкретного класса. Иногда, имея дело со сторонними классами, для которых у вас нет исходного кода, выбор делается за вас. Например, если сторонний класс не предоставляет никаких методов установки, то внедрение конструктора может быть единственной доступной формой DI.

Другие вопросы по теме