自动装配: Spring IoC 容器提供了对相互协作的Bean进行自动装配的功能。可以自动让Spring通过检查容器中的内容,来替开发人员指定Bean的依赖关系。由于autowire 可以针对单个Bean设置,因此可以让有些Bean使用autowire,有些Bean不使用。autowire的方便之处在于减少或消除对属性或构造器参数的设置,从而简化配置文件。

autowire的五种类型:

1、no :默认值,表明不使用自动装配。可以通过元素显示指定依赖,显示指定可以使配置更灵活、更清晰。

2、byName :根据属性名自动装配。此项将检查容器并查找id 值与属性名完全一致的Bean,将该Bean与属性自动装配。

byName示例:
Film类有如下属性:

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film() {
        super();
        // TODO Auto-generated constructor stub
    }
    ----此后均省略setter,getter----
    }

Koko类:

public class Koko {

    private String name;

    public Koko() {
        super();
        // TODO Auto-generated constructor stub
    }

Lolo类:

public class Lolo {

    private String name;

    public Lolo() {
        super();
        // TODO Auto-generated constructor stub
    }
    }

配置文件(ApplicationContext.xml):

<beans>

    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>

    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>

    <bean id="film" class="com.pojo.Film" autowire="byName">
    </bean>

</beans>

main方法测试:

    public static void main(String[] args) {

        ApplicationContext actx= new    ClassPathXmlApplicationContext("ApplicationContext.xml");
        System.out.println("-----------------");
        Film film1= (Film) actx.getBean("film");
        System.out.println(film1.getKo().getName());
        System.out.println(film1.getLo().getName());
        System.out.println("-----------------");
    }

Console输出
这里写图片描述

修改配置文件:

<beans>

    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="byName">
    </bean>

</beans>

再次运行Console结果
这里写图片描述

3、byType: 如果容器中存在一个与指定属性类型相同的Bean,那么将对该属性自动装配。如果存在多个该类型的Bean,那么将会抛出异常(NoUniqueDefinitionException),若没有找到相匹配的Bean,不会抛出异常,也不会对属性进行设置,此时可以通过设置dependency-check=”objects”让spring抛出异常。

byType示例:
Film类:

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film() {
        super();
        // TODO Auto-generated constructor stub
    }
}

配置文件:

<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="byType">
    </bean>
</beans>

Console
这里写图片描述

存在多个与该属性类型相同的Bean时:
修改配置文件:容器中存在两个Lolo类型的Bean

<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo1" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="lo2" class="com.pojo.Lolo">
        <property name="name" value="怪怪"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="byType">
    </bean>
</beans>

Console
这里写图片描述

不存在与该属性类型相同的Bean时:
修改配置文件:容器中不存在Lolo类型的Bean

<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="byType">
    </bean>
</beans>

console:这里写图片描述

4、constructor: 与byType的方式类似,不同之处在于它应用于构造器的参数,根据构造器的参数类型进行自动装配。如果在容器中没有找到与构造器参数类型一致的Bean,那么将会抛出异常。

(1)Film构造器参数的数量与属性的数量相同

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
    }
    public Film() {
        super();
        // TODO Auto-generated constructor stub
    }
}
配置文件:
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

Spring根据Film构造器每个参数的类型,在容器中匹配,对film Bean进行装配
console:这里写图片描述

(2)Film构造器参数的数量比属性的数量少

public class Film {

    private Lolo lo;
    private Koko ko;
    //构造器中只有lo属性
    public Film(Lolo lo) {
        super();
        this.lo = lo;
    }

    public Film() {
        super();
    }
}
配置文件:
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

console:这里写图片描述
构造器参数中没有ko属性,spring没有对这个属性进行装配

(3)只有默认的构造器时:

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film() {
        super();
    }
}
配置文件:
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

console:这里写图片描述
至于原因嘛,自己猜!

(4)一次蛋疼的纯属娱乐的测试

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo) {
        super();
        this.lo = lo;
    }
    public Film(Koko ko) {
        super();
        this.ko = ko;
    }
    public Film() {
        super();
    }
}
配置文件
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

console:这里写图片描述
film的lo属性没有装配,ko属性装配了

我们修改Film的那几个构造器的顺序

public class Film {

    private Lolo lo;
    private Koko ko;
    //改变一下顺序
    public Film(Koko ko) {
        super();
        this.ko = ko;
    }
    public Film(Lolo lo) {
        super();
        this.lo = lo;
    }
    public Film() {
        super();
    }
}
配置文件不变

再看结果
这里写图片描述
film的Ko属性没有被装配,lo属性装配了

后续的构造器中参数对应的属性被装配了,前面的没有被装配,是不是很有意思

(5)回到第(1)种情形,但容器中有多个相同类型的Bean

//注释掉默认的构造方法
public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
    }
/**
    public Film() {
        super();
    }
*/
}
配置文件进行修改,容器中有多个Lolo类型的Bean
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo1" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean>
    <bean id="lo2" class="com.pojo.Lolo">
        <property name="name" value="怪怪"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

console
这里写图片描述
第二个异常:

这里写图片描述

继续测试,取消默认构造方法的注释

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
    }
    public Film() {
        super();
        // TODO Auto-generated constructor stub
    }
    配置文件不变

console:
这里写图片描述
个人理解为按照第一个构造方法的参数匹配行不通,就使用默认的构造方法进行constructor自动装配,两个属性就全变成了null(这只是个人的理解,还请大神指点迷津)

(6)容器中不存在构造器参数中某一类型的Bean时

//注释掉默认构造方法
public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
    }
    /**
    public Film() {
        super();
    }
    */
}
修改配置文件:删除Lolo类型的Bean
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="film" class="com.pojo.Film" autowire="constructor">
    </bean>
</beans>

Console:
这里写图片描述

第二个异常:
这里写图片描述
因为我们用的ApplicationContext接口,在初始化应用上下文时会实例化所有singleton Bean,而film设置了custructor自动装配,容器中缺少Lolo类型的bean ,也就报出了异常(4、constructor: 与byType的方式类似,不同之处在于它应用于构造器的参数,根据构造器的参数类型进行自动装配。如果在容器中没有找到与构造器参数类型一致的Bean,那么将会抛出异常。)

继续测试,取消Film类默认构造方法的注释

public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
    }
    public Film() {
        super();
        // TODO Auto-generated constructor stub
    }
}
配置文件不变

console:
这里写图片描述
没有抛出异常,两个属性值全为null,估计也是参照了默认的构造方法进行自动装配

5、autodetect: 通过Bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现类中有默认的构造器,那么将使用byType方式。

autodetect示例:

类中没有默认的构造器时

//注释默认的构造器
public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
        System.out.println("使用了constructor");
    }
    /**
    public Film() {
        super();
        System.out.println("使用了byType");
    }
    */
}
配置文件:
<beans>
    <bean id="ko" class="com.pojo.Koko">
        <property name="name" value="蛇蛇"/>
    </bean>
    <bean id="lo" class="com.pojo.Lolo">
        <property name="name" value="皮皮"/>
    </bean> 
    <bean id="film" class="com.pojo.Film" autowire="autodetect">
    </bean>
</beans>

console:
这里写图片描述

类中存在默认构造器时

//取消默认构造器的注释
public class Film {

    private Lolo lo;
    private Koko ko;

    public Film(Lolo lo, Koko ko) {
        super();
        this.lo = lo;
        this.ko = ko;
        System.out.println("使用了constructor");
    }
    public Film() {
        super();
        System.out.println("使用了byType");
        // TODO Auto-generated constructor stub
    }
}
配置文件不变

console:
这里写图片描述

结语:感谢您阅读,以上纯属个人学习理解,毕竟水平有限,如有错误,还请您指点迷津!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐