基于构造器(或静态工厂方法)的依赖注入
基于构造器的注入:容器通过调用指定参数的构造器完成bean的实例化,并且通过构造器的参数完成依赖注入。(静态工厂方法与构造器的行为基本一致)
举例:
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
构造器参数解析:容器调用“哪一个”构造器。
策略:通过类型匹配。通过构造器注入时,根据传入的参数的类型,匹配构造器,如果找不到,就会报错。
<!-- 用于参数传递的两个bean -->
<bean id="arg1" class="SpringTest.ConBasedDI.ConArgOne"></bean>
<bean id="arg2" class="SpringTest.ConBasedDI.ConArgTwo"></bean>
<!-- 第一个测试bean,调用<init>(ConArgOne, ConArgOne) -->
<bean id="test1" class="SpringTest.ConBasedDI.TestConDI">
<constructor-arg ref="arg1"/>
<constructor-arg ref="arg1"/>
</bean>
<!-- 第二个测试bean,调用<init>(ConArgOne, ConArgTwo) -->
<bean id="test2" class="SpringTest.ConBasedDI.TestConDI">
<constructor-arg ref="arg1"/>
<constructor-arg ref="arg2"/>
</bean>
<!-- 第三个测试bean,调用<init>(ConArgTwo, ConArgOne) -->
<bean id="test3" class="SpringTest.ConBasedDI.TestConDI">
<constructor-arg ref="arg2"/>
<constructor-arg ref="arg1"/>
</bean>
Java代码:
package SpringTest.ConBasedDI;
public class TestConDI {
public TestConDI(ConArgOne arg1, ConArgOne arg2) {
System.out.println("TestConDI(ConArgOne, ConArgOne)");
}
public TestConDI(ConArgOne arg1, ConArgTwo arg2){
System.out.println("TestConDI(ConArgOne, ConArgTwo)");
}
public TestConDI(ConArgTwo arg1, ConArgOne arg2) {
System.out.println("TestConDI(ConArgTwo, ConArgOne)");
}
}
当启动容器时,运行结果:
匹配时,根据多个constructor-arg子标签指定多个参数类型,子标签的顺序匹配构造器参数的顺序。
使用index属性调整顺序,如果没有用使用index属性,则默认是按照标签排列的顺序进行匹配,如果设置了index属性,则按照index值(从0开始)进行匹配
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="1" value="42"/>
<constructor-arg index="0" value="7500000"/>
</bean>
相当于
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg value="7500000"/>
<constructor-arg value="42"/>
</bean>
参数继承问题
对于上面这个例子,没有让ConArgOne和ConArgTwo具有继承关系。
如果让ConArgTwo继承ConArgOne呢?
扫描二维码关注公众号,回复:
9106786 查看本文章
运行结果没有变化。
请注意这个配置
<bean id="test2" class="SpringTest.ConBasedDI.TestConDI">
<constructor-arg ref="arg1"/>
<constructor-arg ref="arg2"/>
</bean>
继承之后TestConDI(ConArgOne, ConArgOne) 和 TestConDI(ConArgOne, ConArgTwo)都符合这个配置,但还是调用了TestConDI(ConArgOne, ConArgTwo)。
如果有多个选择,容器会帮我们匹配类型更精确的。
确定简单值的类型。
对于引用类型,匹配构造器的时候根据引用的bean类型即可。但是对于简单类型来说,并不能确定它的类型。
举个例子:
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
按照上面的配置方法,可以这样配置。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg value="7500000"/>
<constructor-arg value="42"/>
</bean>
可以看到,简单的使用value属性是不能确定类型的。运行可能并不会出错
使用type属性指定类型:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
使用name属性指定参数名:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
举例(基于构造器注入 + 基于静态工厂方法注入)
基于构造器注入
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
基于静态工厂方法注入
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}