public class Chinese implements Person { private Axe axe; // 默认的构造器 public Chinese() { } // 构造注入所需的带参数的构造器 public Chinese(Axe axe) { this.axe = axe; } // 实现Person接口的useAxe方法 @Override public void useAxe() { // 调用axe的chop()方法 // 表明Person对象依赖于axe对象 System.out.println(axe.chop()); } }
无须再提供设置axe属性的setter方法,仅仅提供了一个带Axe属性的构造器,Spring将通过该构造器为chinese注入所依赖的Bean实例
<?xml version="1.0" encoding="UTF-8"?> <!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 --> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans "> <!-- 配置chinese实例 --> <bean> <!-- 使用构造注入,为chinese实例注入stoneAxe实例 --> <constructor-arg ref="stoneAxe" /> </bean> <!-- 配置stoneAxe实例 --> <bean /> </beans>
<constructor-arg.../>元素指定了一个构造器参数,该参数类型是Axe,这指定Spring调用Chinese类里带一个Axe参数的构造器来创建chinese实例,因为使用了有参数的构造器创建实例,所以当Bean实例被创建完成后,该Bean的依赖关系已经设置完成
配置<constructor-arg.../>元素时可指定一个index属性,用于指定该构造参数值将作为第几个构造参数值;如index=“0”表明该构造参数值将作为第一个构造参数
执行效果与使用设置注入时的执行效果完全一样。区别在于:创建Person实例中Axe属性的时机不同-----设置注入是先通过无参数的构造器创建一个Bean实例,然后调用对应的setter方法注入依赖关系;而构造注入则直接调用有参数的构造器,当Bean实例创建完成后,已经完成了依赖关系的注入
四、两种注入方式的对比
相比之下,设值注入有如下优点:
与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受、通过setter方法设定依赖关系显得更加直观、自然
对于复杂的依赖关系,若采用构造注入,会导致构造器过于臃肿,难以阅读;Spring在创建Bean实例时,需同时实例化其依赖的全部实例,因而导致性能下降
尤其是在某些属性可选的情况下,多参数的构造器更加笨重
相比之下,构造注入有如下优点:
可在构造器中决定依赖关系的注入顺序,优先依赖的优先注入
对于依赖关系无需变化的Bean,构造注入更有用处;因为没有setter方法,所有的依赖关系全部在构造器内设定。因此,无须担心后续的代码对依赖关系产生破坏
依赖关系只能在构造器设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则
一般采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑设值注入