No abuses de los campos privados que obtienes / establece por reflexión
Usar la reflexión como se hace en varias respuestas aquí es algo que podríamos evitar.
Aporta un pequeño valor aquí mientras presenta múltiples inconvenientes:
- detectamos problemas de reflexión solo en tiempo de ejecución (ej .: campos que ya no existen)
- Queremos encapsulación, pero no una clase opaca que oculte las dependencias que deberían ser visibles y que la clase sea más opaca y menos verificable.
- Fomenta el mal diseño. Hoy declaras a
@Value String field
. Mañana puede declararlos 5
o mencionarlos 10
en esa clase y es posible que ni siquiera se dé cuenta de que disminuye el diseño de la clase. Con un enfoque más visible para establecer estos campos (como el constructor), lo pensará dos veces antes de agregar todos estos campos y probablemente los encapsulará en otra clase y los usará @ConfigurationProperties
.
Haga que su clase sea comprobable tanto unitaria como en integración
Para poder escribir tanto pruebas unitarias simples (es decir, sin un contenedor de Spring en ejecución) como pruebas de integración para su clase de componente Spring, debe hacer que esta clase sea utilizable con o sin Spring.
Ejecutar un contenedor en una prueba unitaria cuando no es necesario es una mala práctica que ralentiza las compilaciones locales: no es necesario.
Agregué esta respuesta porque ninguna respuesta aquí parece mostrar esta distinción y, por lo tanto, dependen de un contenedor en ejecución sistemáticamente.
Así que creo que debería mover esta propiedad definida como interna de la clase:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
en un parámetro constructor que será inyectado por Spring:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
Ejemplo de prueba unitaria
Puede crear instancias Foo
sin Spring e inyectar cualquier valor property
gracias al constructor:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
Ejemplo de prueba de integración
Puede inyectar la propiedad en el contexto con Spring Boot de esta manera simple gracias al properties
atributo de @SpringBootTest
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
Podría usar como alternativa, @TestPropertySource
pero agrega una anotación adicional:
@SpringBootTest
@TestPropertySource("property.value=dummyValue")
public class FooTest{ ...}
Con Spring (sin Spring Boot), debería ser un poco más complicado, pero como no usé Spring sin Spring Boot desde hace mucho tiempo, no prefiero decir algo estúpido.
Como nota al margen: si tiene muchos @Value
campos para establecer, extraerlos en una clase anotada @ConfigurationProperties
es más relevante porque no queremos un constructor con demasiados argumentos.