Java Spring @Autowired 字段 - 哪个访问修饰符是私有的还是包私有的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19682293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 19:22:01  来源:igfitidea点击:

Spring @Autowired fields - which access modifier, private or package-private?

javaspringunit-testingprivateaccess-modifiers

提问by vikingsteve

Let's say that we use the @Autowiredannotation over various fields in a class, and that we didn't write setters or constructors that can also set the fields.

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

Question - what should the access modifier be, privateor package-private(i.e. none) ?

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

For example:

例如:

public class MyClass {
    @Autowired
    private MyService myService;
}

vs

对比

public class MyClass {
    @Autowired
    MyService myService;
}

In the first case (privatefields) Spring uses reflection to wire up the field, even if it doesn't have a setter.

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

The second case (package-privatefields) allows us to be able to access those fields (for example, to set up mocks) if we need to extend the class for testing purposes.

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

So both cases work fine, but which is more recommended, particularly with regards to testing?

所以这两种情况都可以正常工作,但更推荐哪种情况,特别是在测试方面?

采纳答案by Simon Verhoeven

The first case also allows you to inject mocks depending on the framework. For example using the @InjectMocksannotation of Mockito. You also have ReflectionTestUtils.setFieldin Spring test, ...

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

I'm personally not too fond of modifying classes too much for testing purposes, so I would go for the first case. But at the end of the day this mostly depends on your preferred test framework.

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

回答by trf

I generally prefer having the field private and using setter injection:

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

public class MyClass {

    private MyService myService;

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

allowing the service to be @Autowired, but set with a mocked instance for unit testing.

允许服务@Autowired,但设置为单元测试的模拟实例。

回答by Debojit Saikia

So both cases work fine, but which is more recommended, particularly with regards to testing?

所以这两种情况都可以正常工作,但更推荐哪种情况,特别是在测试方面?

I think the properties should be private:

我认为属性应该是private

@Autowired
private MyService myService;

As it is always good to have getter methods to provide access to the properties instead of allowing other classes to have direct access to them.

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

And for testing purposes, injection of mocksof private propertieswill work the same way as that of package-privateproperties.

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

For example, with Mockito, you can inject a mock of private MyServiceinto MyClassas this:

例如,Mockito你可以注入的模拟private MyServiceMyClass就象这样:

public class MyClassTest {

    @Mock
    MyService service;

    @InjectMocks
    MyClass serv = new MyClass();

    @Before
    public void init() {
    MockitoAnnotations.initMocks(this);
    }
}

回答by 30thh

I would generally NOT use @Autowired for private fields or methods. @Autowired means, somebody from outside will set this field. "Private" on the other hand means nobody except this class is allowed to use it.

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

Mixing @Autowired and private can theoretically cause problems, if the JIT compiler somehow optimizes this code. It can be a Java Memory Model concurrency related problem, which will be production-only and impossible-to-reproduce.

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

I would make the Autowired fields at least package visible. As free bonus it will allow to write unit tests without tricks and workarounds.

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

UPDATE:Additionally I would declare such fields as volatileto avoid Java Memory Model related visibility conflicts. Spring developers do some tricks to make autowired fields work without explicitly synchronizing the access, but I am not sure these tricks are working smoothly in any JVM on any hardware.

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

回答by Jean-Michel Bernard


I would rather use private on @Autowired fields, for a few reasons:


我宁愿在 @Autowired 字段上使用 private ,原因如下:

  • I use these fields for dependency injection, generally in service classes, to use other service classes. In that case I want to keep those fields to the current class.
  • Also, extending this class can lead to different logic, so maybe another implementation of the @Autowired fields is needed, hence the private instead of package-private.
  • Furthermore, when refactoring, it helps to see when such a field is not used anymore, as package-private fields don't show a warning when unused (assuming your IDE is Eclipse - I actually don't know for other IDEs).
  • 我将这些字段用于依赖注入,通常在服务类中,以使用其他服务类。在这种情况下,我想将这些字段保留在当前类中。
  • 此外,扩展此类会导致不同的逻辑,因此可能需要@Autowired 字段的另一种实现,因此使用私有而不是包私有。
  • 此外,在重构时,有助于查看何时不再使用此类字段,因为包私有字段在未使用时不会显示警告(假设您的 IDE 是 Eclipse - 我实际上不知道其他 IDE)。