首页 > 其他分享 >4. DI相关内容

4. DI相关内容

时间:2023-06-23 17:12:45浏览次数:33  
标签:属性 DI 数据类型 bean 内容 类型 相关 注入 setter

我们先来思考

  • 向一个类中传递数据的方式有几种?

    • 普通方法(set 方法)
    • 构造方法
  • 依赖注入描述了在容器中建立 bean 与 bean 之间的依赖关系的过程,如果 bean 运行需要的是数字或字符串呢?

    • 引用类型
    • 简单类型(基本数据类型与 String)

Spring 就是基于上面这些知识点,为我们提供了两种注入方式,分别是:

  • setter 注入

    • 简单类型
    • 引用类型
  • 构造器注入

    • 简单类型
    • 引用类型

1. setter 注入

  1. 对于 setter 方式注入引用类型的方式之前已经学习过,快速回顾下:
  • 在 bean 中定义引用类型属性,并提供可访问的set方法
public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
  • 配置中使用property 标签 ref属性注入引用类型对象
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
    <property name="bookDao" ref="bookDao"/>
</bean>

<bean id="bookDao" class="com.itheima.dao.imipl.BookDaoImpl"/>

1.1 注入引用数据类型

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

1.2 注入简单数据类型

思考:

引用类型使用的是<property name="" ref=""/>​,简单数据类型还是使用 ref 么?

ref 是指向 Spring 的 IOC 容器中的另一个 bean 对象的,对于简单数据类型,没有对应的 bean 对象,该如何配置?

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <property name="databaseName" value="mysql"/>
     	<property name="connectionNum" value="10"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

注意:两个 property 注入标签的顺序可以任意。

对于 setter 注入方式的基本使用就已经介绍完了,

  • 对于引用数据类型使用的是<property name="" ref=""/>
  • 对于简单数据类型使用的是<property name="" value=""/>

2. 构造器注入

2.1 构造器注入引用数据类型

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>
</beans>

说明:

标签

  • name 属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
  • ref 属性指向的是 spring 的 IOC 容器中其他 bean 对象。

2.2 构造器注入多个引用数据类型

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
</beans>

说明:这两个<contructor-arg>​ 的配置顺序可以任意

2.3 构造器注入多个简单数据类型

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <constructor-arg name="databaseName" value="mysql"/>
        <constructor-arg name="connectionNum" value="666"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
</beans>

说明:这两个<contructor-arg>​ 的配置顺序可以任意

上面已经完成了构造函数注入的基本使用,但是会存在一些问题:

image

  • 当构造函数中方法的参数名发生变化后,配置文件中的 name 属性也需要跟着变
  • 这两块存在紧耦合,具体该如何解决?

在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家都以了解为主。

方式一:删除 name 属性,添加 type 属性,按照类型注入

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <constructor-arg type="int" value="10"/>
    <constructor-arg type="java.lang.String" value="mysql"/>
</bean>
  • 这种方式可以解决构造函数形参名发生变化带来的耦合问题
  • 但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现了

方式二:删除 type 属性,添加 index 属性,按照索引下标注入,下标从 0 开始

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <constructor-arg index="1" value="100"/>
    <constructor-arg index="0" value="mysql"/>
</bean>
  • 这种方式可以解决参数类型重复问题
  • 但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题

介绍完两种参数的注入方式,具体我们该如何选择呢?

  1. 强制依赖使用构造器进行,使用 setter 注入有概率不进行注入导致 null 对象出现

    • 强制依赖指对象在创建的过程中必须要注入指定的参数
  2. 可选依赖使用 setter 注入进行,灵活性强

    • 可选依赖指对象在创建过程中注入的参数可有可无
  3. Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨

  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用 setter 注入完成可选依赖的注入

  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供 setter 方法就必须使用构造器注入

  6. 自己开发的模块推荐使用 setter 注入

3. 关于 setter 注入和构造器注入的小结

  • setter 注入

    • 简单数据类型

      <bean ...>
          <property name="" value=""/>
      </bean>
      
    • 引用数据类型

      <bean ...>
          <property name="" ref=""/>
      </bean>
      
  • 构造器注入

    • 简单数据类型

      <bean ...>
          <constructor-arg name="" index="" type="" value=""/>
      </bean>
      
    • 引用数据类型

      <bean ...>
          <constructor-arg name="" index="" type="" ref=""/>
      </bean>
      
  • 依赖注入的方式选择上

    • 建议使用 setter 注入
    • 第三方技术根据情况选择

4. 自动装配

前面花了大量的时间把 Spring 的注入去学习了下,总结起来就一个字麻烦

问:麻烦在哪?

答:配置文件的编写配置上。

问:有更简单方式么?

答:有,自动配置

4.1 什么是依赖自动装配?

IoC 容器根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中的过程称为自动装配

4.2 自动装配方式有哪些?

  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配

4.3 完成自动装配的配置

自动装配只需要修改 applicationContext.xml 配置文件即可:

(1)将<property>​ 标签删除

(2)在<bean>​ 标签中添加 autowire 属性

首先来实现按照类型注入的配置

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

</beans>

注意事项:

  • 需要注入属性的类中对应属性的 setter 方法不能省略
  • 被注入的对象必须要被 Spring 的 IOC 容器管理
  • 按照类型在 Spring 的 IOC 容器中如果找到多个对象,会报NoUniqueBeanDefinitionException

一个类型在 IOC 中有多个对象,还想要注入成功,这个时候就需要按照名称注入,配置方式为:

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/>

</beans>

注意事项:

  • 按照名称注入中的名称指的是什么?

    ​​image​​

    • bookDao 是 private 修饰的,外部类无法直接方法

    • 外部类只能通过属性的 set 方法进行访问

    • 对外部类来说,setBookDao 方法名,去掉 set 后首字母小写是其属性名

      • 为什么是去掉 set 首字母小写?
      • 这个规则是 set 方法生成的默认规则,set 方法的生成是把属性名首字母大写前面加 set 形成的方法名
    • 所以按照名称注入,其实是和对应的 set 方法有关,但是如果按照标准起名称,属性名和 set 对应的名是一致的

  • 如果按照名称去找对应的 bean 对象,找不到则注入 Null

  • 当某一个类型在 IOC 容器中有多个对象,按照名称注入只找其指定名称对应的 bean 对象,不会报错

两种方式介绍完后,以后用的更多的是按照类型注入。

最后对于依赖注入,需要注意一些其他的配置特征:

  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型的 bean 唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于 setter 注入与构造器注入,同时出现时自动装配配置失效

5. 集合注入

常见的集合类型

  • 数组
  • List
  • Set
  • Map
  • Properties

5.1 注入数组类型数据

<property name="array">
    <array>
        <value>100</value>
        <value>200</value>
        <value>300</value>
    </array>
</property>

5.2 注入 List 类型数据

<property name="list">
    <list>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>chuanzhihui</value>
    </list>
</property>

5.3 注入 Set 类型数据

<property name="set">
    <set>
        <value>itcast</value>
        <value>itheima</value>
        <value>boxuegu</value>
        <value>boxuegu</value>
    </set>
</property>

5.4 注入 Map 类型数据

<property name="map">
    <map>
        <entry key="country" value="china"/>
        <entry key="province" value="henan"/>
        <entry key="city" value="kaifeng"/>
    </map>
</property>

5.5 注入 Properties 类型数据

<property name="properties">
    <props>
        <prop key="country">china</prop>
        <prop key="province">henan</prop>
        <prop key="city">kaifeng</prop>
    </props>
</property>

说明:

  • property 标签表示 setter 方式注入,构造方式注入 constructor-arg 标签内部也可以写<array>​、<list>​、<set>​、<map>​、<props>​ 标签
  • List 的底层也是通过数组实现的,所以<list>​ 和<array>​ 标签是可以混用
  • 集合中要添加引用类型,只需要把<value>​ 标签改成<ref>​ 标签,这种方式用的比较少

标签:属性,DI,数据类型,bean,内容,类型,相关,注入,setter
From: https://www.cnblogs.com/NorthPoet/p/17499353.html

相关文章

  • 3. IOC相关内容
    1.bean相关配置‍对于bean的配置中,主要会讲解​bean基础配置​,bean的别名配置​,bean的作用范围配置​(重点),这三部分内容:1.1bean基础配置(id与class)bean标签的功能如图:​​‍这其中需要大家重点掌握的是:bean标签的id和class属性的使用。思考:class属......
  • 常见的coding技巧
    一、常见的coding技巧1、使用assert断言使用场景:当我们不希望某件事情发生时,我们就使用断言,断言里面的判断条件可为任意的判断语句。当发生时,编译器会自动报错,并且会锁定到具体的行数。2、const修饰指针技巧当const放在*的左边时,限制的是指针指向的内容,不能通过指针变量改变指针指......
  • Predicate.test和直接用boolean有什么区别
    在Java中,Predicate接口和直接使用boolean类型的变量的主要区别在于它们的使用场景和灵活性。使用boolean类型的变量通常用于表示一个简单的逻辑条件,例如判断一个数是否为偶数。这种情况下,我们可以直接使用if语句或三元运算符来判断条件,并返回一个布尔值。而Predicate......
  • redis基础
    1. 什么时redis  1Redis是一个基于内存的key-value结构数据库。●基于内存存储, 读写性能高●适合存储热点数据( 热点商品、资讯、新闻)●企业应用广泛2. redis入门   22.1 redis简介  2Redis is an open source (BSD licensed), in-memory data structure st......
  • 计算机科学|人工智能相关领域历史最全免费课程整理分享
        计算机科学是系统性研究信息与计算的理论基础以及它们在计算机系统中如何实现与应用的实用技术的学科。它通常被形容为对那些创造、描述以及转换信息的算法处理的系统研究。计算机科学包含很多分支领域;有些强调特定结果的计算,比如计算机图形学;而有些是探讨计算问题的性质,比......
  • 中文文本纠错相关经典论文、数据集、系统等资源分享
       中文文本纠错又分为中文拼写纠错(ChineseSpellingCheck,CSC)和语法纠错(GrammaticalErrorCorrection,GEC)。中文拼写纠错任务对中文文本中的拼写纠错(别字、别词)进行检测和纠正。语法纠错任务纠正文本中不同类型的错误,包括拼写、标点、语法等类型错误。    本资源整理......
  • 历史最全DL相关书籍、课程、视频、论文、数据集、会议、框架和工具整理分享
       本文整理了与深度学习、人工智能相关丰富的内容,涉及人工智能相关的思维导图(+100张AI思维导图),深度学习相关的免费在线书籍、课程、视频和讲座、论文、教程、研究人员、网站、数据集、会议、框架、工具等资源。    内容整理自网络,源地址:https://github.com/Niraj-Lunav......
  • 历史最全ChatGPT、LLM相关书籍、论文、博客、工具、数据集、开源项目等资源整理分享
    ChatGPT是一个生成型预训练变换模型(GPT),使用基于人类反馈的监督学习和强化学习在GPT-3.5之上进行了微调。这两种方法都使用了人类训练员来提高模型的性能,通过人类干预以增强机器学习的效果,从而获得更为逼真的结果。在监督学习的情况下,模型被提供了这样一些对话,在对话中训练......
  • 历史最全最新时间序列分析相关必读论文、教程及综述资源整理分析
    本资源整理了用于时间序列分析(AI4TS)的AI的论文列表(包含可用代码)、教程和关于最近综述论文,包括时间序列、时空数据、事件数据、序列数据、时间点过程等,相关TopAIConferencesandJournals,一旦被接受的论文在相应的顶级AI会议/期刊上公布,就会尽快(最早)更新。希望此列表对......
  • 推荐系统徐偏差(debias)相关的技术、论文及代码整理分享
    推荐系统作为解决信息过载的一种重要手段,已经在不同的应用场景下取得了不错的效果。近些年来关于推荐系统的研究主要集中在如何设计更好的模型来适应用户行为数据,进而提升推荐质量。然而,由于用户行为数据是观察所得(Observational)而不是实验所得(Experimental),因此会存在各种......