简体   繁体   English

如何正确地将许多服务注入 Spring MVC 控制器?

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

I have created Spring MVC application that has 3 user types.我创建了具有 3 种用户类型的 Spring MVC 应用程序。 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, eg delegate services to other services or create more controllers?这甚至可以接受还是在这种情况下我应该重构我的代码,例如将服务委托给其他服务或创建更多控制器?

You answered this well yourself!你自己回答的很好! Spring addresses exactly this concern in the docs here in the box titled Constructor-based or setter-based DI?春天正是地址在文档这种担心在这里在框中名为基于构造函数或setter基于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. Spring 团队通常提倡构造函数注入,因为它可以让您将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。 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?".使用SOLID原则并思考“我正在创建的班级的一项工作是什么?”。

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.总之,根据文档,如果存在许多 DI,您可以评估每个 DI 并尝试使用基于集合和/或基于构造函数。 The documentations eplain which one to use below:文档说明以下使用哪一个:

Constructor-based or setter-based DI?基于构造函数还是基于 setter 的 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.由于您可以混合使用基于构造函数和基于 setter 的 DI,因此根据经验,对强制依赖项使用构造函数,对可选依赖项使用 setter 方法或配置方法是一个很好的经验法则。 Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency.请注意,在 setter 方法上使用 @Required 注释可用于使属性成为必需的依赖项。

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. Spring 团队通常提倡构造函数注入,因为它可以让您将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。 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. Setter 注入应该主要仅用于可以在类中分配合理默认值的可选依赖项。 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. setter 注入的一个好处是 setter 方法使该类的对象可以在以后重新配置或重新注入。 Management through JMX MBeans is therefore a compelling use case for setter injection.因此,通过 JMX MBean 进行管理是 setter 注入的一个引人注目的用例。

Use the DI style that makes the most sense for a particular class.使用对特定类最有意义的 DI 样式。 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.例如,如果第三方类不公开任何 setter 方法,则构造函数注入可能是 DI 的唯一可用形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM