22

假设我们@Autowired在类中的各个字段上使用了注解,并且我们没有编写也可以设置字段的 setter 或构造函数。

问题 - 访问修饰符应该是什么,private或者package-private(即没有)?

例如:

public class MyClass {
    @Autowired
    private MyService myService;
}

对比

public class MyClass {
    @Autowired
    MyService myService;
}

在第一种情况下(private字段),Spring 使用反射来连接字段,即使它没有设置器。

如果我们需要扩展类以进行测试,则第二种情况(package-private字段)允许我们能够访问这些字段(例如,设置模拟)。

所以这两种情况都很好,但哪个更推荐,特别是在测试方面?

4

5 回答 5

9

所以这两种情况都很好,但哪个更推荐,特别是在测试方面?

我认为属性应该是private

@Autowired
private MyService myService;

因为拥有 getter 方法来提供对属性的访问而不是允许其他类直接访问它们总是好的。

出于测试目的,注入 ofmocks的工作方式与注入属性private properties的方式相同。package-private

例如,使用,Mockito您可以像这样注入一个模拟:private MyServiceMyClass

public class MyClassTest {

    @Mock
    MyService service;

    @InjectMocks
    MyClass serv = new MyClass();

    @Before
    public void init() {
    MockitoAnnotations.initMocks(this);
    }
}
于 2013-10-30T12:44:49.537 回答
8

我通常更喜欢将字段设为私有并使用 setter 注入:

public class MyClass {

    private MyService myService;

    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }
}   

允许服务为@Autowired,但设置一个模拟实例以进行单元测试。

于 2013-10-30T12:43:08.207 回答
6

第一种情况还允许您根据框架注入模拟。例如使用@InjectMocksMockito 的注解。你也有ReflectionTestUtils.setField在 Spring 测试中,...

我个人不太喜欢为了测试目的而过多地修改类,所以我会选择第一种情况。但归根结底,这主要取决于您首选的测试框架。

于 2013-10-30T12:41:43.063 回答
4

我通常不会将 @Autowired 用于私有字段或方法。@Autowired 的意思是,外面的人会设置这个字段。另一方面,“私人”意味着除了这个类之外没有人可以使用它。

如果 JIT 编译器以某种方式优化此代码,则混合 @Autowired 和 private 理论上会导致问题。它可能是与 Java 内存模型并发相关的问题,这将是仅限生产且无法重现的问题。

我会让 Autowired 字段至少包可见。作为免费奖励,它将允许在没有技巧和变通方法的情况下编写单元测试。

更新:此外,我会声明此类字段volatile以避免与 Java 内存模型相关的可见性冲突。Spring 开发人员在不显式同步访问的情况下使用一些技巧来使自动装配字段工作,但我不确定这些技巧在任何硬件上的任何 JVM 中都能顺利工作。

于 2018-02-23T08:59:40.280 回答
1


出于以下几个原因,我宁愿在 @Autowired 字段上使用 private:

  • 我使用这些字段进行依赖注入,通常在服务类中,以使用其他服务类。在这种情况下,我想将这些字段保留在当前类中。
  • 此外,扩展此类可能会导致不同的逻辑,因此可能需要 @Autowired 字段的另一个实现,因此是私有的而不是包私有的。
  • 此外,在重构时,有助于查看何时不再使用此类字段,因为包私有字段在未使用时不会显示警告(假设您的 IDE 是 Eclipse - 我实际上不知道其他 IDE)。
于 2018-07-12T08:52:10.707 回答