详解Spring中Bean的自动装配~


  • 自动装配是Spring知足bean依赖的一种方式
  • Spring会在上下文中自动寻找,而且自动给bean装配属性

1. 环境搭建

一我的有猫和狗两个宠物java

结构图
image-20200805152406109
Cat.javaweb

package pojo;

public class Cat {
    public void shout() {
        System.out.println("喵~");
    }
}

Dog.javaspring

package pojo;

public class Dog {
    public void shout() {
        System.out.println("汪~");
    }
}

People.javasvg

package pojo;

public class People {
    private Cat cat;
    private Dog dog;
    private String name;

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

    public String getName() {
        return name;
    }
}

beans.xml测试

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="cat" class="pojo.Cat"/>
    <bean id="dog" class="pojo.Dog"/>
    <bean id="people" class="pojo.People">
        <property name="name" value="zsr"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>
    </bean>
</beans>

MyTest.javaui

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.People;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getDog().shout();
        people.getCat().shout();
        System.out.println(people.getName());
    }
}

测试:this

image-20200805152749240

到此环境搭建成功!spa



2. byName、byType

上述代码中,ref就是寻找对应的cat和dog对象;若是有一种机制,可以自动在bean里面寻找咱们要设置的cat或者dog,自动装配,就不用写下面的那两行代码了!这就引入了自动装配指针

咱们更改一下.xml文件,删除那两行代码,加入autowire属性,发现有几种能够选择,这里先选择byName
image-20200805153956150code

<bean id="cat" class="pojo.Cat"/>
<bean id="dog" class="pojo.Dog"/>
<bean id="people" class="pojo.People" autowire="byName">
    <property name="name" value="zsr"/>
</bean>

再次运行测试类,依旧成功,说明咱们的cat和dog被自动设置到了people中
image-20200805153732343
那咱们再更改一下,将dog改成dog1

<bean id="cat" class="pojo.Cat"/>
<bean id="dog1" class="pojo.Dog"/>
<bean id="people" class="pojo.People" autowire="byName">
    <property name="name" value="zsr"/>
</bean>

再进行测试,发现空指针异常
image-20200805153919732
为何??

byName:根据属性名自动装配,检查IoC容器并根据名字查找与属性彻底一致的bean,并将其与属性自动装配。

所以bean的id只有为dog或者cat才可以被找到


咱们再改一下,将byName改成byType

<bean id="cat" class="pojo.Cat"/>
<bean id="dog" class="pojo.Dog"/>
<bean id="people" class="pojo.People" autowire="byType">
    <property name="name" value="zsr"/>
</bean>

再次运行,又成功了
image-20200805161016746
byType:根据属性类型自动装配

  • 若是容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配
  • 若是存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;
  • 若是没有找到相匹配的bean,则什么事都不发生

必须保证类型全局惟一,若是多加一个dog,则报错:
image-20200805161547606
能够省略id

<bean class="pojo.Cat"/>
<bean class="pojo.Dog"/>
<bean id="people" class="pojo.People" autowire="byType">
    <property name="name" value="zsr"/>
</bean>

小结

  • byName的时候,须要保证全部bean的id惟一,而且这个bean id须要和实体类中对应的属性名相同
  • byName的时候,须要保证全部bean的class惟一,而且这个bean id须要和自动注入属性的类型一致;能够省略id


3. 使用注解实现自动装配

jdk1.5支持注解,Spring2.5支持注解

要使用注解

  1. xml中导入约束

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
  2. xml中配置注解支持

    <context:annotation-config/>

@Autowired

  • 直接在属性上使用便可,此时就能够省略set方法
  • 也能够在set方法上使用(适用于在set方法里面写一些处理逻辑的状况)
    image-20200805194313281
    beans.xml
<context:annotation-config/>

<bean id="cat1" class="pojo.Cat"/>
<bean id="dog1" class="pojo.Dog"/>
<bean id="people" class="pojo.People">
    <property name="name" value="zsr"/>
</bean>

运行测试类,成功
image-20200805194601311
自动装配环境很复杂的状况下:假设此时有两个cat和dog对象

<context:annotation-config/>

<bean id="cat1" class="pojo.Cat"/>
<bean id="cat2" class="pojo.Cat"/>
<bean id="dog1" class="pojo.Dog"/>
<bean id="dog2" class="pojo.Dog"/>
<bean id="people" class="pojo.People">
    <property name="name" value="zsr"/>
</bean>

发现直接爆红了
image-20200805194806760
这是由于没法匹配到对应的属性,@Autowired 默认经过 byType 的方式实现,若是有多个对象,则经过 byName 查找,若是都找不到,则报错;

此时经过有两个相同类型的对象,经过类型没法找到,bean id也不与属性名相同,经过名字也找不到,因此报错;

这时候就须要配合@Qualifier来使用,指定惟一的bean对象来注入
image-20200805195309327
再次运行,便可成功


@Qualifier还能够设置required属性值为false 容许属性值为null
image-20200805220439391


@Resource

咱们将上述的Autowired换成Resource
image-20200805213027370
xml文件为

<context:annotation-config/>

<bean id="cat1" class="pojo.Cat"/>
<bean id="cat2" class="pojo.Cat"/>
<bean id="dog1" class="pojo.Dog"/>
<bean id="dog2" class="pojo.Dog"/>
<bean id="people" class="pojo.People">
    <property name="name" value="zsr"/>
</bean>

直接运行
image-20200805213349045
发现报错了,这是由于咱们没法匹配到对应的属性,@Resource 默认经过 byName 的方式实现,若是找不到名字, 则经过 byType 实现!若是两个都找不到,就会报错

此时,名字cat1/cat2/dog1/dog2不匹配,且每一个类型的bean不惟一,因此经过名字和类型都找不到,所以报错

若是咱们将其中一个bean的id改成对应的属性名catdog

<bean id="cat" class="pojo.Cat"/>
<bean id="cat2" class="pojo.Cat"/>
<bean id="dog" class="pojo.Dog"/>
<bean id="dog2" class="pojo.Dog"/>
<bean id="people" class="pojo.People">
    <property name="name" value="zsr"/>
</bean>

再次运行,成功了
image-20200805213800158
这是由于咱们经过名字找到了
咱们还有另外一种解决方式,不用更改bean的id,咱们在@Resource里面添加name属性
image-20200805214155735
经过设置name属性指定装配的对象

此时再运行,成功注入
image-20200805215434616



小结

@Autowired和@Resource的相同点

  • 都是用于自动装配的,均可以放在属性字段set方法

@Autowired和@Resource的区别

  • @Autowired为Spring提供的注解,@Resource为java提供的注解
  • @Autowired 默认经过 byType 的方式实现,若是有多个对象,则经过 byName 查找,若是都找不到,则报错;此时能够用@Qualifier指定惟一的bean对象
  • @Resource 默认经过 byName 的方式实现,若是找不到名字, 则经过 byType 实现!若是两个都找不到,就会报错