injection how dependency bean annotation spring dependency-injection constructor autowired

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.