详解 Spring 中 Bean 的自动装配

程序员考拉

共 8329字,需浏览 17分钟

 · 2021-08-20

公众号关注 “GitHub今日热榜
设为 “星标”,带你挖掘更多开发神器!





    

  • 自动装配是Spring满足bean依赖的一种方式    

  • Spring会在上下文中自动寻找,并且自动给bean装配属性


1. 环境搭建


 一个人有猫和狗两个宠物


结构图:



Cat.java


package pojo;

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


Dog.java


package pojo;

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


People.java


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.java


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


测试:



到此环境搭建成功!


2. byName、byType



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


我们更改一下.xml文件,删除那两行代码,加入autowire属性,发现有几种可以选择,这里先选择byName



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


再次运行测试类,依旧成功,说明我们的cat和dog被自动设置到了people中



那我们再更改一下,将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>


再进行测试,发现空指针异常



为什么??


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>


再次运行,又成功了



byType:根据属性类型自动装配


  • 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配

  • 如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;

  • 没有找到相匹配的bean,则什么事都不发生


必须保证类型全局唯一,如果多加一个dog,则报错:



可以省略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支持注解


要使用注解:


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">


xml中配置注解支持


<context:annotation-config/>


@Autowired


  • 直接在属性上使用即可,此时就可以省略set方法

  • 也可以在set方法上使用(适用于在set方法里面写一些处理逻辑的情况)

 

   

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>


运行测试类,成功



自动装配环境很复杂的情况下:假设此时有两个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>


发现直接爆红了



这是因为无法匹配到对应的属性,@Autowired 默认通过 byType 的方式实现,如果有多个对象,则通过 byName 查找,如果都找不到,则报错;


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


这时候就需要配合@Qualifier来使用,指定唯一的bean对象来注入



再次运行,即可成功


@Qualifier还可以设置required属性值为false 允许属性值为null



@Resource


我们将上述的Autowired换成Resource



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>


直接运行



发现报错了,这是因为我们无法匹配到对应的属性,@Resource 默认通过 byName 的方式实现,如果找不到名字, 则通过 byType 实现!如果两个都找不到,就会报错


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


如果我们将其中一个bean的id改为对应的属性名cat和dog


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


再次运行,成功了



这是因为我们通过名字找到了


我们还有另一种解决方式,不用更改bean的id,我们在@Resource里面添加name属性



通过设置name属性指定装配的对象


此时再运行,成功注入



小结


@Autowired和@Resource的相同点:


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


@Autowired和@Resource的区别:


  • @Autowired为Spring提供的注解,@Resource为java提供的注解

  • @Autowired 默认通过 byType 的方式实现,如果有多个对象,则通过 byName 查找,如果都找不到,则报错;此时可以用@Qualifier指定唯一的bean对象

  • @Resource 默认通过 byName 的方式实现,如果找不到名字, 则通过 byType 实现!如果两个都找不到,就会报错




作者:Baret-H

出处:blog.csdn.net/qq_45173404/article/details/107826456










关注GitHub今日热榜,专注挖掘好用的开发工具,致力于分享优质高效的工具、资源、插件等,助力开发者成长!







点个在看,你最好看


浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报