La DI basada en constructor la realiza el contenedor llamando a un constructor con una cantidad de argumentos, cada
uno de los cuales representa una dependencia. Llamar a un método de fábrica static
con argumentos
específicos para crear un bean es casi equivalente, y este análisis trata los argumentos del constructor y del
método de fábrica static
de la misma manera. El siguiente ejemplo muestra una clase cuya dependencia
sólo se puede inyectar a través del constructor:
public class SimpleMovieLister {
// SimpleMovieLister has a dependency on MovieFinder
private final MovieFinder movieFinder;
// constructor so that the Spring container can inject MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the embedded MovieFinder is omitted...
}
// constructor so that the Spring container can inject MovieFinder
class SimpleMovieLister(private val movieFinder: MovieFinder) {
// business logic that actually uses the embedded MovieFinder is omitted...
}
Tenga en cuenta que esta clase no tiene nada de especial. Es un POJO (objeto Java simple) que no depende de interfaces de contenedor, clases base o anotaciones específicas.
Resolviendo argumentos del constructor
La asignación de resolución de argumentos del constructor se produce utilizando el tipo de argumento. Si no hay ambigüedad potencial en los argumentos del constructor de una definición de bean, entonces el orden en el que se definen los argumentos del constructor en la definición del bean es el orden en el que esos argumentos se pasan al constructor correspondiente cuando se crea el bean. Considere la siguiente clase:
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
paquete x.y
clase CosaUno(cosaDos: CosaDos, cosaTres: CosaTres)
Suponiendo que las clases ThingTwo
y ThingThree
no están relacionadas por herencia, no hay
ambigüedad potencial. Por lo tanto, la siguiente configuración funciona bien y no es necesario especificar
explícitamente índices o tipos de argumentos del constructor en el elemento <constructor-arg/>
.
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</frijol>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
Si se proporciona una referencia a otro bean, entonces se conoce el tipo, por lo que puede ocurrir un mapeo (como
sucedió en el ejemplo anterior). Si se utiliza un tipo simple, como <value>true</value>
,
Spring no puede determinar el tipo del valor y, por lo tanto, no puede realizar la coincidencia de tipos sin ayuda
externa. Considere la siguiente clase:
package examples;
public class ExampleBean {
// Number of years to calculate the final answer
private final int years;
// The answer to the main question of life, the universe and everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
package examples
class ExampleBean(
private val years: Int, // Number of years to calculate the final answer
private val ultimateAnswer: String // The answer to the main question of life, the universe and everything
)
En el escenario anterior, el contenedor puede habilitar la asignación de tipos a tipos simples si el tipo del
argumento del constructor se especifica explícitamente usando el atributo type
, como se muestra en el
siguiente ejemplo:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
Puede utilizar el atributo index
para establecer explícitamente el índice de los argumentos del
constructor, como se muestra en el siguiente ejemplo:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
Además de eliminar la ambigüedad de varios valores primos, especificar un índice elimina la ambigüedad si un constructor tiene dos argumentos del mismo tipo.
También puede utilizar el nombre del parámetro del constructor para resolver conflictos de valores, como se muestra en el siguiente ejemplo:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg nombre="años" valor="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
Tenga en cuenta que para que esto funcione de inmediato, el código debe compilarse con el indicador de depuración habilitado para que Spring pueda buscar el nombre del parámetro en el constructor. Si no puede o no quiere compilar su código con el indicador de depuración, puede usar annotation @ConstructorProperties JDK para nombrar explícitamente los argumentos de su constructor. Entonces la clase de muestra debería verse así:
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
package examples
class ExampleBean
@ConstructorProperties("years", "ultimateAnswer")
constructor(val years: Int, val ultimateAnswer: String)