• Spring 的注入


    目录

    一、注入(Injection)

     1、什么是注入

    (1)为什么需要注入

    (2)如何进行注入

    2、Spring 注入原理分析(简易版)

    二、Set 注入详解

    1、JDK 内置类型

    (1)String + 8种基本类型

    (2)数组

    (3)Set 集合

    (4)List 集合

    (5)Map 集合

    (6)properties

    (7)复杂的 JDK 类型

    2、用户自定义类型

    第一种方式: 

    第二种方式:

    3、Set 注入的简化写法

    (1)基于属性简化

    (2)基于 p 命名空间简化

    三、构造注入

    1、开发步骤

    2、构造方法重载

    (1)参数个数不同​编辑

    (2)构造参数个数相同时 

    3、注入总结

    四、反转控制 与 依赖注入

    1、反转控制(IoC Inverse of Control)

    2、依赖注入(Dependency Injection DI)


    一、注入(Injection)

     1、什么是注入

    所谓的注入,指的就是,通过 Spring 的工厂及配置文件为所创建对象的成员变量赋值

    (1)为什么需要注入

    我们原来对一个对象的变量进行赋值使用的是 get 和 set 的方法来完成的:

    但是需要注意的是,此时我们所完成的赋值,是我们通过代码来完成的,并不是我们所说的注入

    注入指的是通过 Spring 的配置文件对成员变量进行赋值

    我们直接通过 set 来进行赋值的效果,是可以达到预期的,但是它并不好

    因为它存在耦合,主要体现在

    比如,日后如果这个名字不想叫馒头警告了,想叫别的名字,那么这个名字得在代码中更改,实际上这个名字在更改的过程中,就存在耦合了因为改代码涉及到重新编译,重新输出


    (2)如何进行注入

    1、类的成员变量提供 set,get 方法

    2、 配置 Spring 的配置文件

    配置文件之前,得先有对应的 get 和 set 方法!!!

    此时,就完成了通过配置文件给 id 属性和 name 属性的赋值


    2、Spring 注入原理分析(简易版)

     

    Spring 通过底层调用对象属性对应的 set 方法来完成成员变量的赋值,这种方式我们也称之为 set 注入


    二、Set 注入详解

    成员变量的类型,有很多种,我们之前讲的是针对 int 和 String 类型的,所以标签使用的是 value

    那如果类型变成了别的呢?比如:double ,char ,List.....

    此时 里面的标签可能就要发生改变了,因为它可能是一个集合,也可能是一个数组,甚至还有可能是一个我们自己定义的类型....

    针对于不同类型的成员变量,我们在 标签中,需要嵌套其它标签

    1. <property>
    2. xxxxx
    3. </property>

    针对不同类型的成员变量,它有两种分类,一种叫做 JDK 类型的变量,也就是 java 原生的成员变量,另一种叫做 用户自定义类型 ,也就是我们自己提供的变量类型

    那么接下来,我们就要针对这些不同的类型,来学习在 set 注入过程当中我们应该在  标签中嵌套什么标签来对对应的变量类型进行赋值


    1、JDK 内置类型

    (1)String + 8种基本类型

    这里所嵌套的标签也就是我们之前所讲的 value 标签

    <value>sunsvalue>

    (2)数组

    如果现在有一个 数组 类型的成员变量又该如何赋值呢?

    1. <property name="emails">
    2. <list>
    3. <value>123456@qq.comvalue>
    4. list>
    5. property>

    (3)Set 集合

    当变量类型为 Set 集合时:

    1. <property name="tels">
    2. <set>
    3. <value>1381111value>
    4. <value>1391111value>
    5. <value>1661111value>
    6. set>
    7. property>

    这个时候,实际上就是为 set 集合赋值三个元素,因为 set 集合是无序的,所以我们所赋值的这三个元素,虽然我们按照顺序来进行赋值,但是未来在遍历的时候,它有可能不按照这个顺序进行注入

    如果此时,这里有一个重复性的数据

    比如这个手机号出现了三次,那么按照 set 集合的语义,它会帮我们把重复的数据过滤掉,最终实际上 set 集合在输出的时候,还是之前那三个元素的部分,后面重复的号码被自动过滤掉了

    注意:Set 集合中的 Set 标签是固定的,但是里面嵌套的 value 标签却是不一定的

    我们此时在 set 里面嵌套的是 value 标签是因为我们定义的泛型是 String ,而  String 是应该用 value,所以我们现在之所以能够嵌套 value 标签使用,原因在于 Person 当中 Set 的泛型是 String 的


    (4)List 集合

    当类型为 list 时:

     List 集合所使用的 list 标签和我们刚才学的数组一样,都是 list 标签

    1. <property name="adresses">
    2. <list>
    3. <value>shengzhenvalue>
    4. <value>beijingvalue>
    5. <value>shanghaivalue>
    6. list>
    7. property>

    List 集合是有序的!!!

    所以我们在这里按照这个顺序进行赋值,那么最后 List 集合进行遍历的时候,也一定会按照这个集合进行输出

    List 集合是可以重复的!!!

    所以即便有三个一样的元素,那么最后输出的时候,这三个元素都会进行输出

    和 Set 集合相同的是,我们之所以能在 list 里面嵌套 value 标签,是因为此时我们的泛型是 String 类型的


    (5)Map 集合

    当类型是 Map 类型时:

    我们之前学习 Map 的时候,就已经学习到:Map 是由键值对组成的,那么作为 map 来讲,这个键值对应该封装成一个对象,这个对象我们在之前的学习内容中就已经接触过了:Map.entry

    一个 entry ,封装的就是一个键值对 

    1. <property name="qqs">
    2. <map>
    3. <entry>
    4. <key>
    5. <value>123value>
    6. key>
    7. <value>12415513value>
    8. entry>
    9. map>
    10. property>

    注意:此时在 key 中嵌套 value 也是因为此时的泛型是 String 类型的

    同样的,因 为 值 的泛型也是 String,所以后面使用的也是 value


    (6)properties

    Properties类型 是一个 特殊的Map 特殊的地方在于:key=String value=String
    1. <property name="p">
    2. <props>
    3. <prop key="key1">value1prop>
    4. <prop key="key2">value2prop>
    5. props>
    6. property>

     这里的每一个 prop 都对应了一个键值对


    (7)复杂的 JDK 类型

    需要程序员自定义类型转换器,进行处理


    2、用户自定义类型

    第一种方式: 

    1、为成员变量提供 set ,get 方法

    2、 在配置文件中进行注入(赋值)   

    1. <bean id="userService" class="UserServiceImpl">
    2. <property name="userDAO">
    3. <bean class="UserDAOImpl"/>
    4. property>
    5. bean>


    第二种方式:

    第一种方式存在的一些问题:

    1、配置文件代码冗余

    2、被注入的对象(userDAO)被多次创建,浪费(JVM)内存资源

    第二种方式的步骤与之前一样:

    1、为成员变量提供 get ,set 方法

    2、配置文件中进行配置(这里有区别)

    先创建 userDAO 对象,再来创建 userService 对象,然后

    1. <bean id="userDAO" class="xxx.UserDAOImpl"/>bean>
    2. <bean id="userService" class="xxx.UserServiceImpl">
    3. <property name="userDAO">
    4. <ref bean="userDAO"/>
    5. property>
    6. bean>
    7. <bean id="orderService" class="xxx.OrderServiceImpl">
    8. <property name="userDAO">
    9. <ref bean="userDAO"/>
    10. property>
    11. bean>
    12. #Spring4.x 废除了 <ref local=""/> 基本等效 <ref bean=""/>

    userDAO 被多个引用,解决了代码冗余的问题,同时自始至终只用了一个 bean 标签,创建了一个 DAO 对象,也解决了内存资源浪费的问题


    3、Set 注入的简化写法

    (1)基于属性简化

    1. JDK类型注⼊
    2. <property name="name">
    3. <value>sunsvalue>
    4. property>
    5. <property name="name" value="suns"/>
    6. 注意:value属性 只能简化 8种基本类型+String 注⼊标签
    7. ⽤户⾃定义类型
    8. <property name="userDAO">
    9. <ref bean="userDAO"/>
    10. property>
    11. <property name="userDAO" ref="userDAO"/>

    (2)基于 p 命名空间简化 

    1. JDK类型注⼊
    2. <bean id="person" class="xxxx.Person">
    3. <property name="name">
    4. <value>sunsvalue>
    5. property>
    6. bean>
    7. <bean id="person" class="xxx.Person" p:name="suns"/>
    8. 注意:value属性 只能简化 8种基本类型+String 注⼊标签
    9. ⽤户⾃定义类型
    10. <bean id="userService" class="xx.UserServiceImpl">
    11. <property name="userDAO">
    12. <ref bean="userDAO"/>
    13. property>
    14. bean>
    15. <bean id="userService" class="xxx.UserServiceImpl" p:userDAO-ref="userDAO"/>

    三、构造注入

    注入:通过 Spring 的配置文件为成员变量赋值

    Set 注入:Spring 调用 Set 方法,通过配置文件为成员变量赋值

    构造注入:Spring 调用构造方法,为成员变量赋值

    1、开发步骤

    (1)提供有参构造方法

    因为我们得通过有参的构造方法来为对应的成员变量进行赋值

    (2)提供Spring 的配置文件进行配置

    一个  标签,对应一个构造方法中的构造参数,个数以及顺序和构造参数的顺序是一样的


    2、构造方法重载

     当构造方法发生了重载之后,我们要如何进行注入呢?

    构造方法重载:方法名一样,但是参数表不                                                                              同

    而所谓的参数表不同指的是参数的类型不同,参数的个数不同,参数的顺序不同,那么一旦构造方法发生重载,我们在注入的时候又要注意哪些细节呢?

    (1)参数个数不同

    通过控制  标签的数量来进行区分 

    1. <bean id="customer2" class = "Constructor.customer">
    2. <constructor-arg>
    3. <value>xiaoheivalue>
    4. constructor-arg>
    5. bean>

    (2)构造参数个数相同时 

    然后,我们再对 age 进行实验:

    1. <bean id="customer" class = "Constructor.Customer">
    2. <constructor-arg>
    3. <value>18value>
    4. constructor-arg>
    5. bean>

    此时就发现了一个问题:这个 18 并没有给 age 赋值,而是给 name 赋值了

    这是因为 Spring 优先选择了上面的构造方法进行使用

    那么如何解决这个方法呢?

    name 和 age 最大的区别就是类型不同,所以这个时候我们要额外进行一个限定:指定类型

    在   后面新增一个属性,叫做 type

    此时就能解决问题了


    3、注入总结

    在未来写项目的时候,是使用 Set 注入更多还是 构造注入 更多呢?

    使用 Set 注入更多

    1、构造注入比较麻烦(存在重载的问题)

    2、Spring 框架底层,大量应用了 set 注入

    综上,在未来,set 注入使用的更多


    四、反转控制 与 依赖注入

    1、反转控制(IoC Inverse of Control)

    控制:对于成员变量赋值的控制权

    反转控制:把对于成员变量赋值的控制权,从代码中转移到 Spring 的工厂和配置文件中完成

    优点:解耦合

    底层实现:工厂设计模式


    2、依赖注入(Dependency Injection DI)

    注入:通过 Spring 的工厂及配置文件为对象(Bean / 组件)的成员变量赋值

    依赖:当一个类需要另一个类的时候,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过 Spring 进行注入(赋值)

  • 相关阅读:
    altera FPGA 程序固化命令
    tomcat7插件的引入
    @Resource和@Autowired
    MogDB企业应用 之 七种武器
    java计算机毕业设计五金机电市场批发零售管理信息系统源码+数据库+系统+lw文档+mybatis+运行部署
    react基本使用、jsx语法介绍
    群晖NAS DSM7.2.1安装宝塔之后无法登陆账号密码问题解决
    5款提高工作效率的免费工具推荐
    SQLServer下载与安装
    常见web安全及防护原理
  • 原文地址:https://blog.csdn.net/weixin_73616913/article/details/132788506