Spring @Полученные поля - какие модификаторы доступа, частные или пакетно-частные?

Скажем, что мы используем аннотацию @Autowired по различным полям в классе и что мы не записываем сеттеры или конструкторы, которые также могут устанавливать поля.

Вопрос: какой должен быть модификатор доступа, private или package-private (т.е. нет)?

Например:

public class MyClass {
    @Autowired
    private MyService myService;
}

против

public class MyClass {
    @Autowired
    MyService myService;
}

В первом случае (private поля) Spring использует отражение для подключения поля, даже если у него нет setter.

Второй случай (package-private) позволяет нам иметь доступ к этим полям (например, для настройки mocks), если нам нужно расширить класс для целей тестирования.

Таким образом, оба случая работают нормально, но что более рекомендуется, особенно в отношении тестирования?

Ответ 1

Первый случай также позволяет вам вводить mocks в зависимости от структуры. Например, используя аннотацию @InjectMocks Mockito. У вас также есть ReflectionTestUtils.setField в тесте Spring,...

Я лично не слишком люблю слишком много менять классы для тестирования, поэтому я бы пошел на первый случай. Но в конце дня это в основном зависит от вашей предпочтительной структуры тестирования.

Ответ 2

Таким образом, оба случая работают нормально, но что более рекомендуется, особенно в отношении тестирования?

Я думаю, что свойства должны быть private:

@Autowired
private MyService myService;

Как всегда полезно иметь методы getter для предоставления доступа к свойствам вместо того, чтобы другие классы имели прямой доступ к ним.

И для целей тестирования вставка mocks of private properties будет работать так же, как и свойства package-private.

Например, с помощью Mockito вы можете ввести макет private MyService в MyClass следующим образом:

public class MyClassTest {

    @Mock
    MyService service;

    @InjectMocks
    MyClass serv = new MyClass();

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

Ответ 3

Я обычно предпочитаю, чтобы поле было приватным и использовало инъекцию установщика:

public class MyClass {

    private MyService myService;

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

позволяя услуге быть @Autowired, но настроен с помощью изделенного экземпляра для модульного тестирования.