How do I properly inject many services into Spring MVC controller?

时间:2019-01-09 21:41:54

标签: java spring model-view-controller dependency-injection controller

I have created Spring MVC application that has 3 user types. I've created separate controllers for each of them. Now in each of them, I have to inject service classes so I have done it like this:

@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";
}

This code is using field injection. Which is, as I now learned, a solution that should be avoided and replaced with constructor injection. So I've Autowired a constructor with all of these fields like this:

@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;
}

Is this a good solution, creating such verbose constructor in such simple code? And what if I had even more services in my code? Is this even acceptable or in this case should I refactor my code, e.g. delegate services to other services or create more controllers?

2 个答案:

答案 0 :(得分:1)

You answered this well yourself! Spring addresses exactly this concern in the docs here in the box titled Constructor-based or setter-based 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.

That is, you should ideally refactor. Used SOLID principles and think "what is the one job of the class I'm creating?".

答案 1 :(得分:0)

In conclution, according to the documentation if exist many DI you can evaluate every one and try to use set based and/or contructor based. The documentations eplain which one to use below:

Constructor-based or setter-based DI?

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency.

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.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.