• SpringBean的装配与注入



    一、Spring的特点

    • 方便解耦,简化开发
    • 方便集成各种优秀框架
    • AOP编程的支持
    • 降低JavaEE API的使用难度
    • 声明式事务的支持
    • 开源项目
    • 方便程序测试

    体系结构图

    在这里插入图片描述

    核心概念

    控制反转(IOC:Inversion of Control):将对象的控制权由硬编码的程序转交给Spring容器

    解释:传统的JavaSE程序通过new关键字进行创建对象,对象的控制权在硬编码的Java程序。实现了IOC设计的Spring程序,对象的控制权在Spring容器。

    Spring配置文件的bean节点相关属性

    • Spring的bean节点中具备很多属性,如下表
    属性名称说明
    id唯一标识;方便在别的地方可以找到这个对象
    class类的全称,注意全称是包名加上类名
    lazy-init是否延迟加载
    init-method对象初始化完成之后就执行的方法
    destroy-method当前对象被销毁之前Spring会自动调用的方法
    scope单例还是多例
    depends-on强制要求实例化这个bean之前必须先实例化另一个bean
    • 其中还有property子节点,property子节点的属性如下
    属性名称说明
    name属性名
    value属性值
    ref对象类型的引入
    • 示例代码:

      • Spring配置文件
    <bean   id="user" class="com.iflytek.entity.User"   init-method="fun1"
    destroy-method="fun2"   scope="prototype" depends-on="dept" >
    <property   name="name" value="张三">property>
    <property   name="age" value="18">property>
    bean>
    <bean   id="dept"   class="com.iflytek.entity.Dept">bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 测试类
    
    public static void   main(String[] args) {
    
     
    
    //   ApplicationContext 是一个接口;不可直接new;可导入源码查看,源码在下载spring的jar中resources结尾的jar包,所以创建实现类对象
    
    //参数为:spring配置文件的文件名称
    
    //注意:ApplicationContext初始化之时;配置的需要spring容器帮助创建的对象也就创建了
    
    ApplicationContext   ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml");
    
    //根据id值来获取spring容器帮助你创建的User对象,需要强转
    
    User   user=(User)ctx.getBean("user");
    
    //打印user对象的相关对象
    
    System.out.println(user);
    
          //User user2=(User)ctx.getBean("user");
    
    //      ((ClassPathXmlApplicationContext)ctx).close();    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 扩展:Spring的上下文也可以同时加载多个Spring的配置文件,例:
    ApplicationContext   ctx=new ClassPathXmlApplicationContext("a.xml","b.xml");
    
    //或:
    
    ApplicationContext   ctx=new ClassPathXmlApplicationContext(new String[] {"a.xml","b.xml"});
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、依赖注入的三种方式

    • 实体类Customer:
    
    package com.entity;
    
     
    
    public class Customer {
    
        private String uname;
    
     
    
        private BankCard bankCard;
    
     
    
        public String getUname() {
    
            return uname;
    
        }
    
     
    
        public void setUname(String uname) {
    
            this.uname = uname;
    
        }
    
     
    
        public BankCard getBankCard() {
    
            return bankCard;
    
        }
    
     
    
        public void setBankCard(BankCard   bankCard) {
    
            this.bankCard = bankCard;
    
        }
    
     
    
        public Customer(String uname) {
    
     
    
            this.uname = uname;
    
        }
    
     
    
        public Customer() {
    
            super();
    
        }
    
     
    
        public Customer(String uname, BankCard   bankCard) {
    
            super();
    
            this.uname = uname;
    
            this.bankCard = bankCard;
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 实体类BankCard
    package com.entity;
    
    public class BankCard {
    
        private String bcId;
    
        private IdCard ic;
    
        public String getBcId() {
    
            return bcId;
    
        }
    
     
    
        public void setBcId(String bcId) {
    
            this.bcId = bcId;
    
        }
    
     
    
        public IdCard getIc() {
    
            return ic;
    
        }
    
     
    
        public void setIc(IdCard ic) {
    
            this.ic = ic;
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 实体类IdCard
    package com.entity;
    
    public class IdCard {
    
        private String idCard;
    
     
    
        public String getIdCard() {
    
            return idCard;
    
        }
    
     
    
        public void setIdCard(String idCard) {
    
            this.idCard = idCard;
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1、Set方法注入

    
    <bean id="cust"   class="com.entity.Customer">
    
      <property name="uname"   value="张学友">property>
    
      <property name="bankCard"   ref="bc">property>
    
    bean>
    
    <bean   id="bc" class="com.entity.BankCard">
    
      <property name="bcId"   value="123456789">property>
    
      <property name="ic"   ref="icc">property>
    
    bean>
    
    <bean   id="icc" class="com.entity.IdCard">
    
      <property name="idCard"   value="1111111111111">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2、构造方法注入

    注意:一定要有该构造方法,index:参数的位置,ref:对象类型的引用,type:参数对象的类型,value:值

    
    <bean id="cust22"   class="com.entity.Customer">
    
      <constructor-arg index="0"   type="String" value="刘德华">constructor-arg>
    
    bean>
    
    <bean id="cust322"   class="com.entity.Customer">
    
      <constructor-arg index="0"   type="String" value="刘德华2">constructor-arg>
    
      <constructor-arg index="1"   type="com.entity.BankCard" ref="bc">constructor-arg>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、 静态工厂注入

    <bean   id="qa" class="com.factory.BankCardFactory"   factory-method="createBankCard">bean>
    
    <bean   id="cust4" class="com.entity.Customer">
    
               <property name="uname"   value="周杰伦">property>
    
               <property   name="bankCard" ref="qa">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意点:
    需要新建一个类,类中包含一个静态方法,factory-method :静态方法名

    package com.factory;
    
    import com.entity.BankCard;
    
    public class BankCardFactory {
    
        public static BankCard createBankCard() {
    
            return new BankCard();
    
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三、复杂数据类型注入

    • 创建班级实体类和学生实体类
      在这里插入图片描述

    1、 数组类型注入

    
    
    
    <bean id="c1" class="com.entity.Clazz">
    
      <property name="clazzName"   value="Java6班">property>
    
      <property name="sname">
    
      
    
                <list>
    
                           <value>jack1value>
    
                           <value>jack2value>
    
                           <value>jack3value>
    
                list>
    
      property>
    
     bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    2、List集合类型注入

    
    <bean id="c1" class="com.entity.Clazz">
    
            <property   name="clazzName" value="Java6班">property>
    
            <property   name="stus">
    
     
    
                <list>
    
                    <ref   bean="s1"/>
    
                    <ref   bean="s2"/>
    
                    <ref   bean="s3"/>
    
                list>
    
            property>
    
    bean>
    
     
    
    <bean id="s1"   class="com.entity.Student">
    
                <property   name="sname" value="jack1">property>
    
    bean>
    
    <bean id="s2" class="com.entity.Student">
    
                <property   name="sname" value="jack2">property>
    
    bean>
    
    <bean id="s3"   class="com.entity.Student">
    
                <property   name="sname" value="jack3">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3、Set集合类型注入

    
    <bean id="c1" class="com.entity.Clazz">
    
            <property   name="clazzName" value="Java6班">property>        
    
            <property   name="stuSet">
    
                <set>
    
                    <ref   bean="s1"/>
    
                    <ref   bean="s2"/>
    
                    <ref   bean="s3"/>
    
                set>
    
            property>
    
    bean>
    
      <bean id="s1"   class="com.entity.Student">
    
                <property   name="sname" value="jack1">property>
    
      bean>
    
      <bean id="s2"   class="com.entity.Student">
    
                <property   name="sname" value="jack2">property>
    
      bean>
    
      <bean id="s3"   class="com.entity.Student">
    
                <property   name="sname" value="jack3">property>
    
               bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4、Map集合类型注入

    <bean   id="c1" class="com.entity.Clazz">
    
            <property   name="clazzName" value="Java6班">property>
    
            <property   name="stuMap">
    
                <map>
    
                    <entry key="1"   value-ref="s1">entry>
    
                    <entry key="2"   value-ref="s2">entry>
    
                    <entry key="3"   value-ref="s3">entry>
    
                map>
    
            property>
    
        bean>
    
        <bean id="s1"   class="com.entity.Student">
    
                <property   name="sname" value="jack1">property>
    
      bean>
    
      <bean id="s2"   class="com.entity.Student">
    
                <property   name="sname" value="jack2">property>
    
      bean>
    
      <bean id="s3"   class="com.entity.Student">
    
                <property   name="sname" value="jack3">property>
    
               bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    5、Date时间类型注入

    • 在学生实体类中添加属性生日
    
    package com.entity;
    
    import java.util.Date;
    
    //学生类
    
    public class Student {
    
      private String sname;//学生姓名
    
      private Date sbirth;      
    
      public Date getSbirth() {
    
                return sbirth;
    
      }
    
      public void setSbirth(Date sbirth) {
    
                this.sbirth = sbirth;
    
      }
    
      public String getSname() {
    
                return sname;
    
      }
    
      public void setSname(String sname) {
    
                this.sname = sname;
    
      }
    
      @Override
    
      public String toString() {
    
                return "Student [sname="   + sname + "]";
    
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • Spring配置文件中
    
    <bean id="s4"   class="com.entity.Student">
    
      <property name="sbirth" >
    
                
    
                <bean   factory-bean="sdf" factory-method="parse">
    
                           <constructor-arg   value="2020-09-09">constructor-arg>
    
                bean>
    
      property>
    
    bean>
    
    <bean id="sdf"   class="java.text.SimpleDateFormat">
    
      <constructor-arg index="0"   name="pattern"   value="yyyy-MM-dd">constructor-arg>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    四、Spring的自动装配

    1、之前注入的写法

    
    <bean id="cust"   class="com.entity.Customer">
    
      <property name="uname"   value="张学友">property>
    
      <property name="bankCard"   ref="bc">property>
    
    bean>
    
    <bean id="bc"   class="com.entity.BankCard">
    
      <property name="bcId"   value="123456789">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2、 升级版——>将ref移除掉(根据类型来自动装配——>byType)

    <bean id="cust"   class="com.entity.Customer" autowire="byType">
    
      <property   name="uname" value="张学友">property>
    
    bean>
    
    <bean id="bc"   class="com.entity.BankCard">
    
      <property   name="bcId" value="123456789">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、根据类型来自动装配的弊端

    当Spring的主配置文件存在两个相同类型时,例如上述例子注入了两个BankCard类型的对象即会产生问题

    
    <bean id="bc"   class="com.entity.BankCard">
    
      <property   name="bcId" value="1111 2222 3333   5555">property>
    
    bean>
    
    <bean id="bankCard"   class="com.entity.BankCard">
    
      <property   name="bcId" value="1111 2222 3333   4444">property>
    
    bean>
    
    <bean id="cust"   class="com.entity.Customer" autowire="byType">
    
      <property   name="uname" value="jack">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4、错误信息

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.entity.BankCard' available: expected single matching bean but found 2: bc,bankCard

    5、 解释

    因为采用的是根据类型来进行自动装配,但是在装配的过程中发现有两个BankCard的类型可以装入,具体装配哪一个就无法确定了,所以就会出现异常信息

    6、 解决方法

    将根据类型自动装配改成根据名称来进行自动装配——>(byName);根据属性的名称与bean节点id的值是否一致来进行自动装配,即Customer中BankCard的属性名称bankCard;那么即会自动装配进id值为bankCard的bean节点对象

    
    <bean id="bc"   class="com.entity.BankCard">
    
      <property   name="bcId" value="1111 2222 3333   5555">property>
    
    bean>
    
    <bean id="bankCard"   class="com.entity.BankCard">
    
      <property   name="bcId" value="1111 2222 3333   4444">property>
    
    bean>
    
    <bean id="cust"   class="com.entity.Customer" autowire="byName">
    
      <property   name="uname" value="jack">property>
    
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    7、 自动装备再升级

    将autowire的属性写入bean中即表示这个bean的注入为自动注入,同时也可以写在Spring的命名空间上,表示全文件都采用自动注入

    8、 总结

    Spring的自动装配共有两种方式,详情见下表

    自动装配特点
    byType根据类型来自动注入对象的文字属性 例如:Customer类的bankCard属性的类型BankCard spring会自动查找spring配置文件中所有符合BankCard类型的bean对象;如果找到一个符合类型的或多个类型都符合,则报错
    byName根据名称来自动注入对象的子对象属性 ;例如:Customer类中有属性名叫bankCard和spring文件中注入的BankCard类的bean的id相同,则自动注入
  • 相关阅读:
    MarqueeView - 跑马灯
    Spring Boot整合Swagger报错:“this.condition“ is null
    Java项目:JSP手机商城管理系统包含前台
    万物皆可集成系列:低代码如何不成为数据孤岛
    一种考虑时空关联的深度学习短时交通流预测方法
    React18入门(第一篇)——JSX、TSX语法详解
    Prompt之美:如何设计提示词让大模型变“聪明”
    关于echarts多选下拉框更改折线图数量变更y轴数量
    进程的内容
    Java 插入公式到PPT幻灯片
  • 原文地址:https://blog.csdn.net/qq_54351538/article/details/127794592