哪种方法是最佳做法?

时间:2017-09-19 12:20:29

标签: java spring dependency-injection

Bean的哪一个定义是最佳实践?为什么?

例如,类型1可用于单元测试而无需创建上下文。

输入1

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

类型2

public class MovieRecommender {

    @Autowired
    public CustomerPreferenceDao customerPreferenceDao;


    // ...

}

5 个答案:

答案 0 :(得分:4)

我会说第一个。不仅仅是因为你可以轻松地测试它,而是因为一个简单的规则

  

在构造函数的末尾,一个对象应该具有实际执行其任务所需的everythig

(对不起,我不记得我在哪里读到它:(无论如何,我认为这是一个很好的规则)

因此,通过以第二种方式实现您的类,您可以创建拥有所需内容的实例。您必须实例化它并设置其依赖项。如果你忘记了最后一部分会怎么样?

这就是为什么我总是推荐构造函数注入并将依赖项设置为final,因此除非在构造函数中设置它们,否则它不会编译

答案 1 :(得分:2)

由于您提到的原因,

向下移动构造函数依赖注入优先于字段依赖注入:您无法将其作为常规POJO进行测试。

根据documentation扩展构造函数与Setter方法依赖注入的讨论:

  

[..]使用构造函数强制执行是一个很好的经验法则   依赖项和setter方法或可选的配置方法   依赖

答案 2 :(得分:1)

我会说第一个更好。

我使用它的主要原因是,设置测试更简单,更清洁。您只需创建模拟的依赖项并将其传递给正在测试的组件的构造函数。

从Spring 4.3开始,具有单个构造函数的类可以省略@Autowired 注释。

所以你可以写:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

还有一招。如果你将它与Lombok的@AllArgsConstructor一起使用,那么你也不必编写constuctor(与字段注入相同),并且你也有测试的方便构造函数。

@AllArgsConstructor
public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao; //injected

}

因此,如果您使用的是Lombok,我会使用构造函数注入+ AllArgsConstructor

还有一些关于这个issue的精彩文章。

答案 3 :(得分:1)

我会建议类型2

因为无论如何你正在使用注释将依赖注入类,这是通过使用 Reflection API 完成的。 ..

因此没有使用构造函数初始化...

如果您不想使用注释,请按照要求使用 -

如果要在通过setter方法创建对象后更改(初始化)值,则转到setter注入..

如果两个注入都可用,则Setter注入会覆盖使用构造函数注入初始化的属性值。

答案 4 :(得分:1)

第一个(也称为构造函数依赖注入)主要是因为它更容易测试。如果你想模拟customerPreferenceDao,你可以模拟它并将其注入MovieRecommender的一个实例。它可以让您更好地控制自己正在做的事情。