Inyección de dependencias II
En la entrada anterior Inyección de dependencias I implementamos este proceso a través del constructor de la clase. Ahora revisaremos los demás métodos que tenemos para inyectar beans, mediante un método setter y mediante cableado automático (autowiring).
Vamos a realizar algunas modificaciones al proyecto anterior para implementar los temas anteriormente mencionados.
Contenido
Inyección mediante método setter
Reglas que se deben cumplir para utilizar este método de inyección.
- La clase debe tener un constructor vacio( sin parametros), esto no implica que no pueda tener constructores con parametros.
- El método setter debe ser public, sin retorno(void), y debe nombrarse igual al atributo precedido por palabra set, ejem: para un atributo edad, public void setEdad(...)
Clase Esfero
En la clase Esfero creada anteriormente, agregamos un constructor vacío y el método setter para el atributo tinta.
public class Esfero{ // .. Codigo anterior // Constructor vacio public Esfero(){} // Metodo setter public void setTinta(Tinta tinta ){ this.tinta = tinta; } }
Ya no será necesario mantener el constructor parametrizado de la entrada anterior, si deseas lo puedes conservar o eliminar.
Contenedor Spring
<beans> <--beans anteriores --> <bean id="miEsfero" class="com.curso.spring.Esfero"> <!--Inyección mediante constructor <constructor-arg ref="miTintaAzul" > </constructor-arg> --> <!--Inyección mediante setter --> <property name="tinta" ref="miTinta" > </property> </bean> </beans>
Reemplazamos <constructor-arg > por <property> para inyectar mediante método setter, el atributo name corresponde al nombre del metodo setter de Esfero sin la palabra set( ejem: setTinta --> tinta) y ref corresponde a un bean Tinta creado anteriormente. Puedes utilizar varias <property> para inyectar beans.
Puedes combinar <constructor-arg > y <property>, una buena practica es utilizar <constructor-arg > para beans que son obligatorio y <property> para beans opcionales.
Cableado automático(autowire)
Permite al contenedor Spring conectar automáticamente las relaciones(dependencias) entre los beans. El cableado automático reduce significativamente la necesidad de especificar argumentos mediante <constructor-arg > o <property>.
Tenemos 4 modos para el cableado automático:
- Default: (por defecto), sin cableado automático, debe utilizar <constructor-arg > o <property> para la inyección.
- byName: autocableado por nombre de propiedad. El Contenedor Spring buscara un bean con el mismo nombre(id) que la propiedad que debe conectarse, utiliza un metodo setter.
- byType: Conecta una propiedad automáticamente si existe un unico bean del tipo de la propiedad en el contenedor.Si existe más de uno, se lanza un error fatal. Utiliza un método setter para inyectar, no es obligatorio que el setter sea nombrado igual a la propiedad precedida de set.
- constructor: Similar a byType pero se aplica a los argumentos del constructor. Si no existe un bean del tipo de argumento del constructor en el contenedor, se generara un error fatal.
Para especificar el modo de conexión automática para un bean utilizamos el atributo autowire del elemento <bean>
Te recomiendo que revises la sección cableado automático de Spring para ver más detalles.
Cableado automático por constructor
<beans> <--beans anteriores --> <bean id="miEsfero" class="com.curso.spring.Esfero" autowire="constructor" > </bean> </beans>
Hemos agregado autowire utilizando constructor para inyectar un bean Tinta, sustituyendo el uso <constructor-arg >.
El contenedor Spring tomará un bean que coincida con el tipo y nombre del parámetro del constructor y lo inyectará. De lo contrario no inyectara ningún bean.
Detalles a tener presente para nuestro ejemplo
Tenemos tres beans tipo Tinta (miTinta, miTintaAzul, miTintaRoja). Ninguno coincide con el nombre del parámetro del constructor Esfero: public Esfero (Tinta tinta), por ello no se inyectará ningún bean Tinta y dará un error NullPointerException al llamar al método verColor() en la clase principal. Tenemos tres soluciones:
- Renombrar uno de los bean Tinta del contenedor: por ejemplo, miTinta renómbrarlo a tinta para que coincida con nombre del parámetro del constructor
- Renombrar el parámetro del constructor: parámetro tinta renómbrarlo algún beans del contenedor (miTinta, miTintaAzul, miTintaRoja). Es lo inverso a la primera solución.
- Si no desea renombrar ninguno de los beans Tinta, agregue el atributo primary= "true" en uno de los <bean> Tinta, Spring tomará ese bean y lo inyectará, solo puede haber un primary= "true" en beans del mismo tipo.
Cableado automático por tipo(byType)
<beans> <--beans anteriores --> <bean id="miEsfero" class="com.curso.spring.Esfero" autowire="byType" > </bean> </beans>
El contenedor Spring creará el bean miEsfero y luego verificará si tiene alguna dependencia establecida mediante método setter, si es así, tomará un bean que coincida con el tipo del parámetro del método setter y lo inyectará. Si existe más de un bean candidato (ósea del mismo tipo), lanzara un error tipo UnsatisfiedDependencyException, ya que no sabe que bean debe inyectar.
Detalles a tener presente para nuestro ejemplo
Los beans miTinta, miTintaAzul, miTintarRoja son del mismo tipo Tinta(Implementan Interface Tinta) ósea tenemos más de un bean para ser inyectado, dará un error. Tenemos dos soluciones
- Eliminar dos de los beans Tinta, con ello solo tendremos un único candidato para ser inyectado.
- Agregar el atributo primary = true en uno de los <bean> Tinta
Cableado automático por nombre(byName)
<beans> <--beans anteriores --> <bean id="miEsfero" class="com.curso.spring.Esfero" autowire="byName" > </bean> </beans>
Similar a la inyección byType, pero el proceso para inyectar el bean cambia, Spring tomará un bean del contenedor cuyo nombre coincida con el nombre de un metodo setter (sin el prefijo set) del bean miEsfero.
Detalles a tener presente para nuestro ejemplo
En Esfero tenemos el método setter llamado setTinta(…) para inyectar la Tinta, pero el nombre del método no coincide con ninguno de los beans Tinta (miTinta, miTintaAzul, miTintaRoja) del contenedor, por ende, debemos renombrar uno de ellos. Por ejemplo, miTinta llamarlo tinta, ahora si coincidirá con setTinta(sin tener en cuenta prefijo set).
Excluir un bean para el cableado automático
Utilice el atributo autowire-candidate = false en el elemento <bean>. Esto hará que esa definición de bean especifica no esté disponible para el cableado automático. Puede serle útil cuando utilice el modo de cableado byType.
Definir un bean principal
Con el atributo primary= true sobre un elemento <bean>, hará que esa definición de bean sea el bean principal a inyectar en caso que Spring encuentra un problema de ambigüedad al momento de resolver una dependencia.
Tenga en cuenta que si define dependencias explicitas con <property> y <constructor-arg> siempre anulan el cableado automático.
Comentarios
Publicar un comentario