Не зловживайте приватними полями, отриманими / заданими за допомогою відображення
Використання рефлексії, як це робиться в декількох відповідях, тут є щось, чого ми могли б уникнути.
Тут він приносить невелику цінність, в той час як представляє багато недоліків:
- ми виявляємо проблеми з відображенням лише під час виконання (наприклад: поля вже не існують)
- Ми хочемо інкапсуляції, але не непрозорого класу, який приховує залежності, які повинні бути видимими і роблять клас більш непрозорим і менш випробуваним.
- це заохочує поганий дизайн. Сьогодні ви оголошуєте
@Value String field
. Завтра ви можете оголосити 5
або 10
про них у тому класі, і ви навіть не можете зрозуміти, що ви зменшуєте дизайн класу. З більш наочним підходом до встановлення цих полів (наприклад, конструктора), ви подумайте двічі перед тим, як додати всі ці поля, і, ймовірно, інкапсулюйте їх в інший клас та використаєте @ConfigurationProperties
.
Зробіть свій клас перевіряючим як унітарним, так і інтеграційним
Щоб мати змогу писати як прості тестові одиниці (тобто без запущеного пружинного контейнера), так і тести інтеграції для вашого компонентного компонента Spring, ви повинні зробити цей клас придатним для використання з Spring або без нього.
Запуск контейнера в одиничному тесті, коли він не потрібен, є поганою практикою, яка сповільнює локальну збірку: цього ви не хочете.
Я додав цю відповідь, тому що жодна відповідь тут не демонструє цієї різниці, і тому вони систематично покладаються на запущений контейнер.
Тому я думаю, що ви повинні перемістити це властивість, визначене як внутрішній клас:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
в параметр конструктора, який буде введено Spring:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
Приклад тестового модуля
Ви можете створювати інстанцію Foo
без Spring та вводити будь-яке значення property
завдяки конструктору:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
Приклад інтеграційного тесту
Ви можете ввести властивість у контекст із Spring Boot таким простим способом завдяки properties
атрибуту @SpringBootTest
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
Ви можете використовувати як альтернативу @TestPropertySource
але це додає додаткову примітку:
@SpringBootTest
@TestPropertySource("property.value=dummyValue")
public class FooTest{ ...}
З Spring (без Spring Boot) це повинно бути трохи складніше, але оскільки я довго не використовував Spring без Spring Boot, я не вважаю за краще думати щось.
Як бічне зауваження: якщо у вас є багато @Value
полів для встановлення, витягнення їх у клас із зауваженнями @ConfigurationProperties
є більш релевантним, оскільки ми не хочемо конструктора з занадто великою кількістю аргументів.