how - spring injection constructor
Spring @Autowire en Propiedades vs Constructor (5)
En realidad, en mi experiencia, la segunda opción es mejor.
Sin la necesidad de
@Autowired
.
De hecho, es más sabio
crear código que no esté demasiado unido al framework
(tan bueno como lo es Spring)
.
Desea un código que intente en la medida de lo posible adoptar un enfoque de
toma de decisiones diferido
.
Eso es tanto
pojo
como sea posible, tanto que el marco puede cambiarse fácilmente.
Por lo tanto, le aconsejaría que cree un archivo de configuración separado y defina su bean allí, así:
En el archivo SomeService.java :
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
En el archivo ServiceConfig.java :
@Config
public class ServiceConfig {
@Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
De hecho, si desea obtener un profundo conocimiento técnico al respecto, existen preguntas de seguridad de subprocesos (entre otras cosas) que surgen con el uso de
Field Injection
(
@Autowired
), según el tamaño del proyecto, obviamente.
Consulte esto
para obtener más información sobre las
ventajas y desventajas de Autowiring
.
En realidad, los chicos clave realmente recomiendan que uses la
inyección de constructor en
lugar de la
inyección
de
campo
Entonces, como he estado usando Spring, si tuviera que escribir un servicio que tuviera dependencias, haría lo siguiente:
@Component
public class SomeService {
@Autowired private SomeOtherService someOtherService;
}
Ahora me he encontrado con código que usa otra convención para lograr el mismo objetivo
@Component
public class SomeService {
private final SomeOtherService someOtherService;
@Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Ambos métodos funcionarán, lo entiendo. Pero, ¿hay alguna ventaja en usar la opción B? Para mí, crea más código en la prueba de clase y unidad. (Tener que escribir el constructor y no poder usar @InjectMocks)
¿Se me escapa algo? ¿Hay algo más que haga el constructor con cable además de agregar código a las pruebas unitarias? ¿Es esta una forma más preferida de hacer una inyección de dependencia?
Sí, la opción B (que se llama inyección de constructor) en realidad se recomienda sobre la inyección de campo, y tiene varias ventajas:
- Las dependencias están claramente identificadas. No hay forma de olvidar uno al probar o instanciar el objeto en cualquier otra circunstancia (como crear la instancia de bean explícitamente en una clase de configuración)
- las dependencias pueden ser finales, lo que ayuda con la robustez y la seguridad del hilo
- No necesita reflexión para establecer las dependencias. InjectMocks todavía se puede usar, pero no es necesario. Puede crear simulacros usted mismo e inyectarlos simplemente llamando al constructor
Vea esta publicación de blog para un artículo más detallado, escrito por uno de los colaboradores de Spring, Olivier Gierke .
Te explicaré en palabras simples:
En la Opción (A),
está permitiendo que cualquiera (en diferentes clases fuera / dentro del contenedor Spring) cree una instancia utilizando el constructor predeterminado (como el
new SomeService()
), que NO es bueno ya que necesita el objeto
SomeOtherService
(como dependencia) para su
SomeService
¿Hay algo más que haga el constructor con cable además de agregar código a las pruebas unitarias? ¿Es esta una forma más preferida de hacer una inyección de dependencia?
La opción (B) es el enfoque preferido,
ya que NO permite crear
SomeService
objeto
SomeService
sin resolver realmente la dependencia
SomeOtherService
.
Autowired
constructores con
Autowired
proporcionan un gancho para agregar código personalizado antes de registrarlo en el contenedor de resorte.
Supongamos que la clase
SomeService
extiende otra clase llamada
SuperSomeService
y tiene algún constructor que toma un nombre como argumento.
En este caso, el constructor
Autowired
funciona bien.
Además, si tiene que inicializar algunos otros miembros, puede hacerlo en el constructor antes de devolver la instancia al contenedor spring.
public class SuperSomeService {
private String name;
public SuperSomeService(String name) {
this.name = name;
}
}
@Component
public class SomeService extends SuperSomeService {
private final SomeOtherService someOtherService;
private Map<String, String> props = null;
@Autowired
public SomeService(SomeOtherService someOtherService){
SuperSomeService("SomeService")
this.someOtherService = someOtherService;
props = loadMap();
}
}
Bueno saber
Si solo hay una llamada de constructor, no es necesario incluir una anotación @Autowired. Entonces puedes usar algo como esto:
@RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
... ejemplo de inyección de Spring Data Repository.