1. Introducción
Podría decirse que uno de los principios de desarrollo más importantes del diseño de software moderno es la inyección de dependencia (DI), que naturalmente fluye de otro principio de importancia crítica: la modularidad.
Este artículo explorará un tipo específico de técnica DI llamada inyección de dependencia basada en constructor dentro de Spring, que en pocas palabras, significa que los componentes requeridos se pasan a una clase en el momento de la instanciación.
Para comenzar, necesitamos importar la dependencia de contexto de primavera en nuestro pom.xml :
org.springframework spring-context 5.2.8.RELEASE
Entonces necesitamos configurar un archivo de configuración . Este archivo puede ser un POJO o, si lo prefiere, un archivo XML.
2. Configuración basada en anotaciones
El archivo de configuración de Java se parece mucho a un objeto Java antiguo con algunas anotaciones adicionales:
@Configuration @ComponentScan("com.baeldung.constructordi") public class Config { @Bean public Engine engine() { return new Engine("v8", 5); } @Bean public Transmission transmission() { return new Transmission("sliding"); } }
Aquí estamos usando anotaciones para notificar al tiempo de ejecución de Spring que esta clase es un proveedor de definiciones de bean ( anotación @Bean ) y que se debe realizar un escaneo de contexto para beans adicionales en el paquete com.baeldung.spring . A continuación, definimos una clase de coche :
@Component public class Car { @Autowired public Car(Engine engine, Transmission transmission) { this.engine = engine; this.transmission = transmission; } }
Spring encontrará nuestra clase Car mientras realiza un escaneo de paquete e inicializará su instancia llamando al constructor anotado @Autowired .
Las instancias de Engine y Transmission se obtendrán llamando a los métodos anotados @Bean de la clase Config . Finalmente, necesitamos arrancar un ApplicationContext usando nuestra configuración POJO:
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Car car = context.getBean(Car.class);
3. Inyección de constructor implícito
A partir de Spring 4.3, las clases con un solo constructor pueden omitir la anotación @Autowired . ¡Un poco de comodidad y eliminación repetitiva!
Además de eso, también a partir de 4.3, la inyección basada en constructor se puede aprovechar en las clases anotadas de @Configuration . Y sí, si dicha clase tiene solo un constructor, la anotación @Autowired también se puede omitir.
4. Configuración basada en XML
Otra forma de configurar el tiempo de ejecución de Spring con la inyección de dependencia basada en el constructor es usar un archivo de configuración XML:
Tenga en cuenta que constructor-arg puede aceptar un valor literal o una referencia a otro bean y que se puede proporcionar un índice y un tipo explícito opcional . Los atributos de tipo e índice se pueden utilizar para resolver la ambigüedad (por ejemplo, si un constructor toma varios argumentos del mismo tipo).
El atributo name también podría usarse para la coincidencia de variables xml con java, pero luego su código debe compilarse con la marca de depuración activada.
Un contexto de aplicación Spring, en este caso, debe iniciarse usando ClassPathXmlApplicationContext :
ApplicationContext context = new ClassPathXmlApplicationContext("baeldung.xml"); Car car = context.getBean(Car.class);
5. Pros y contras
La inyección de constructor tiene algunas ventajas en comparación con la inyección de campo.
El primer beneficio es la capacidad de prueba. Supongamos que vamos a realizar una prueba unitaria de un bean Spring que usa inyección de campo:
public class UserService { @Autowired private UserRepository userRepository; }
Durante la construcción de una instancia de UserService , no podemos inicializar el estado de userRepository . La única forma de lograr esto es a través de la API Reflection, que rompe completamente la encapsulación. Además, el código resultante será menos seguro en comparación con una simple llamada al constructor.
Además, con la inyección de campo, no podemos imponer invariantes a nivel de clase.Por lo tanto, es posible tener una instancia de UserService sin un userRepository correctamente inicializado . Por lo tanto, podemos experimentar excepciones NullPointerException aleatorias aquí y allá. Además, con la inyección de constructores, es más fácil construir componentes inmutables.
Además, el uso de constructores para crear instancias de objetos es más natural desde el punto de vista de la programación orientada a objetos.
Por otro lado, la principal desventaja de la inyección de constructores es su verbosidad, especialmente cuando un bean tiene un puñado de dependencias. A veces puede ser una bendición disfrazada, ya que podemos esforzarnos más para mantener al mínimo el número de dependencias.
6. Conclusión
Este tutorial rápido ha mostrado los conceptos básicos de dos formas distintas de usar la inyección de dependencia basada en constructor utilizando el marco Spring.
La implementación completa de este tutorial se puede encontrar en GitHub.