Spring框架的依赖注入示例

依赖注入主要有两种方式:基于构造函数的、基于set访问器的

DI exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection.

Spring的团队是推荐使用基于构造函数的依赖注入的,因为他可以确保Bean是不可变的组,且所需要的依赖不是空。当我们的构造函数有太多的参数的时候就说明我们的类负担的任务太重,这时候需要考虑,将一个类的功能,分配到不同的类中去。在可选的依赖项注入场景中,他是很有用的,同时我们也可以通过@Required的注解表明,这个依赖时必须的,set形式的注入,是方便后期重新进行配置和更改的。

依赖注入的配置信息可以存在于XML、Java代码、注解中,在写有关bean依赖的信息在bean被创建的时候提供给bean。在我们配置的时候一些属性的值都是字符串的形式,在容器内部实例化的时候都会将之装换为内置的形式,也就是说属性所对应的形式。

当我们通过构造函数注入的时候容易造成循环依赖,这时候我们的程序会报BeanCurrentlyInCreationException的错误,尽管这类的循环以来的错误Spring 框架大概率可以解决,但是真的出现了程序的循环依赖我们可以尝试使用set方法的注入。

  • 基于构造函数的依赖注入(Constructor-based DI)

我们构造函数的每个参数就对应着一个依赖(一个类的变量,需要其他的类/基本类型来赋值),在开发文档关于构造函数的依赖注入中与一句这样的描述,有些不理解:

Calling a static factory method with specific arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a constructor and to a static factory method similarly. 

当参数是自定义类型的时候,只要配置中的与构造函数中的参数不引起歧义,我们在配置中进行依赖注入的配置时仅仅通过ref来指明引用即可:

If no potential ambiguity exists in the constructor arguments of a bean definition, then the order in which the constructor arguments are defined in a bean definition is the order in which those arguments are supplied to the appropriate constructor when the bean is being instantiated.  

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }
}

<beans>
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
    </bean>

    <bean id="bar" class="x.y.Bar"/>

    <bean id="baz" class="x.y.Baz"/>
</beans>

 当我们的参数类型不都是自定义类型时:

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 type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

 当我们有多个相同的类型是,这时候仅仅只通过type就不行了,这时我们可以使用index、name来更好的消除歧义:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

 在开发文档中还给出了构造函数的一个注解@ConstructionProperties ,这个注解是用来将构造函数参数与set方法之间建立起来一种关系,但是现在并不太理解这个的具体作用:

Keep in mind that to make this work out of the box your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you can’t compile your code with debug flag (or don’t want to) you can use@ConstructorProperties JDK annotation to explicitly name your constructor arguments. 

public class ExampleBean {

    // Fields omitted

    @ConstructorProperties({"years", "ultimateAnswer"})
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}
  • 基于set方法的依赖注入(Setter-based dependency injection)

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" 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 void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }
}

当我们在set方法上使用了@Required的时候,这个方法对应的属性就是必须被注入的。

当我们使用静态方法来进行实例化的时候,注入的方式与使用构造函数的是相同的:

<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;
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值