基于构造器(或静态工厂方法)的依赖注入

基于构造器(或静态工厂方法)的依赖注入

基于构造器的注入:容器通过调用指定参数的构造器完成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;
    }
}
发布了213 篇原创文章 · 获赞 116 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq2071114140/article/details/104205233
今日推荐