Spring IoC 基础概念

目录

一、IoC 相关概念

1、什么是 IoC?

IoC Inversion of Control (控制反转/反转控制),注意它是一个技术思想,不是一个技术实现。
描述的事情:Java 开发领域对象的创建,管理的问题。
传统开发方式:比如类 A 依赖于类 B,往往会在类 A 中 new 一个 B 的对象。
IoC 思想下开发方式:我们不用自己去 new 对象了,而是由 IoC 容器(Spring 框架)去帮助我们实例化对象并且管理它,我们需要使用哪个对象,去问 IoC 容器要即可。
我们丧失了一个权利(创建、管理对象的权利),得到了一个福利(不用考虑对象的创建、管理等一系列事情)。

2、为什么叫做控制反转?

控制:指的是对象创建(实例化、管理)的权利。
反转:控制权交给外部环境了(Spring 框架、IoC 容器)。

3、IoC 解决了什么问题?

IoC 解决对象之间的耦合问题。

  1. 其实就是把具体实例化对象的步骤交给容器处理。
  2. 是否单例、是否重新实例化新的对象这些操作也都交给容器负责。
  3. 而要用到的类里的属性也会变成接口,是哪个具体实现类也不需要知晓,到时候直接拿接口向容器要实例化后的对象就行。

下面是用 service 层和 dao 层下的接口、实现类进行举例:

Spring IoC 基础概念

4、IoC 和 DI 的区别

IoC:Inversion of Control(控制反转/反转控制);
DI:Dependancy Injection(依赖注入)。
IoC 和 DI 描述的是同一件事情(对象实例化及依赖关系维护这件事情),只不过⻆度不一样罢了。
IoC 是站在对象的角度,对象实例化及其管理的权利交给了(反转)给了容器。
DI 是站在容器的角度,容器会把对象依赖的其他对象注入(送进去),比如 A 对象实例化过程中因为声明了一个 B 类型的属性,那么就需要容器把 B 对象注入到 A。

二、Spring IoC 基础概念

1、 BeanFactory 与 ApplicationContext 区别:

BeanFactory 是 Spring 框架中 IoC 容器的顶层接口,它只是用来定义一些基础功能,定义一些基础规范,
而 ApplicationContext 是它的一个子接口,所以 ApplicationContext 是具备 BeanFactory 提供的全部功能的;
通常,我们称 BeanFactory 为 SpringIoC 的基础容器,
ApplicationContext 是容器的高级接口,比 BeanFactory 要拥有更多的功能,比如说国际化支持和资源访问(xml,java 配置类)等等。

2、Bean 的 X 及生命周期

1)作用范围的改变

在 spring 框架管理 Bean 对象的创建时,Bean 对象默认都是单例的,但是它支持配置的方式改变作用范围。

范围 说明
singleton (默认值)每个 Spring IoC 容器将单个 bean 定义范围限制到单个对象实例。
protoype 将单个 bean 定义的作用域限定为任意数量的对象实例。
request 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期;也就是说,每个 HTTP 请求都有一个自己的 bean 实例,它是在单个 bean 定义的后面创建。仅在可感知网络的 Spring ApplicationContext 中有效。
session 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。
application 将单个 bean 定义的范围限定为 ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。
websocket 将单个 bean 定义的范围限定为 WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。

应用配置:

<!--配置service对象-->
<bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" 
        scope="singleton"></bean>

2)不同作用范围的生命周期

模式名称 单例模式:singleton 多例模式:prototype
对象出生 当创建容器时,对象就被创建了。 当使用对象时,创建新的对象实例。
对象活着 只要容器在,对象一直活着。 只要对象在使用中,就一直活着。
对象死亡 当销毁容器时,对象就被销毁了。 当对象⻓时间不用时,被 java 的垃圾回收器回收了。
一句话总结 单例模式的 bean 对象生命周期与容器相同。 多例模式的 bean 对象,spring 框架只负责创建,不负责销毁。

3、Bean 标签属性

在基于 xml 的 IoC 配置中,bean 标签是最基础的标签。它表示了 IoC 容器中的一个对象。
换句话说,如果一个对象想让 spring 管理,在 XML 的配置中都需要使用此标签配置,Bean 标签的属性如下:

1)id 属性:

用于给 bean 提供一个唯一标识。在一个标签内部,标识必须唯一。

2)class 属性:

用于指定创建 Bean 对象的全限定类名。

3)name 属性:

用于给 bean 提供一个或多个名称。多个名称用空格分隔。

4)factory-bean 属性:

用于指定创建当前 bean 对象的工厂 bean 的唯一标识。当指定了此属性之后, class 属性失效。

5)factory-method 属性:

用于指定创建当前 bean 对象的工厂方法,如配合 factory-bean 属性使用,则 class 属性失效。如配合 class 属性使用,则方法必须是 static 的。

6)scope 属性:

用于指定 bean 对象的作用范围。通常情况下就是 singleton。当要用到多例模式时,可以配置为 prototype。

7)init-method 属性:

用于指定 bean 对象的初始化方法,此方法会在 bean 对象装配后调用。必须是 一个无参方法。

8)destory-method 属性:

用于指定 bean 对象的销毁方法,此方法会在 bean 对象销毁前执行。它只能为 scope 是 singleton 时起作

三、DI 依赖注入的 xml 配置

1、依赖注入分类

1)按照注入的方式分类

构造函数注入:顾名思义,就是利用带参构造函数实现对类成员的数据赋值。
set 方法注入:它是通过类成员的set方法实现数据的注入。(使用最多的)

2)按照注入的数据类型分类

基本类型和 String

注入的数据类型是基本类型或者是字符串类型的数据。

其他 Bean 类型

注入的数据类型是对象类型,称为其他 Bean 的原因是,这个对象是要求出现在 IoC 容器中的。那么针对当前 Bean 来说,就是其他 Bean 了。

复杂类型(集合类型)

注入的数据类型是 Array,List,Set,Map,Properties 中的一种类型。

2、依赖注入的配置实现之构造函数注入

顾名思义,就是利用构造函数实现对类成员的赋值。
它的使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。
同时需要注意的是,当没有无参构造时,则必须提供构造函数参数的注入,否则 Spring 框架会报错。

public class JdbcAccountDaoImpl implements AccountDao {
    
    private ConnectionUtils connectionUtils;
    
    private String name;
    private int sex;
    private float money;
    
    public JdbcAccountDaoImpl(ConnectionUtils connectionUtils, String name, 
            int sex, float money) {
        this.connectionUtils = connectionUtils;
        this.name = name;
        this.sex = sex;
        this.money = money;
    }
}
<bean id="accountDao" class="com.jason.dao.impl.JdbcAccountDaoImpl" scope="singleton">
    
    <!-- <constructor-arg index="0" ref="connectionUtils"/>
    <constructor-arg index="1" value="zhangsan"/>
    <constructor-arg index="2" value="1"/>
    <constructor-arg index="3" value="100.5"/> -->
    
    <!-- name:按照参数名称注入,index:按照参数索引位置注入 -->
    <constructor-arg name="connectionUtils" ref="connectionUtils"/>
    <constructor-arg name="name" value="zhangsan"/>
    <constructor-arg name="sex" value="1"/>
    <constructor-arg name="money" value="100.5"/>
</bean>

在使用构造函数注入时,涉及的标签是 constructor-arg,该标签有如下属性:

  • name:用于给构造函数中指定名称的参数赋值。
  • index:用于给构造函数中指定索引位置的参数赋值。
  • value:用于指定基本类型或者 String 类型的数据。
  • ref:用于指定其他 Bean 类型的数据。写的是其他 bean 的唯一标识。

3、依赖注入的配置实现之 set 方法注入

顾名思义,就是利用字段的 set 方法实现赋值的注入方式。
此种方法在实际开发中是使用最多的注入方式。

public class JdbcAccountDaoImpl implements AccountDao {
    
    private ConnectionUtils connectionUtils;
    
    private String name;
    private int sex;
    private float money;
    
    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }
    public void setMoney(float money) {
        this.money = money;
    }
}
<bean id="accountDao" class="com.jason.dao.impl.JdbcAccountDaoImpl" scope="singleton">
    
    <!-- 
        set 注入使用 property 标签,
        如果注入的是另外一个 bean 那么使用 ref 属性,
        如果注入的是普通值那么使用的是 value 属性。
     -->
    <property name="connectionUtils" ref="connectionUtils"/>
    <property name="name" value="zhangsan"/>
    <property name="sex" value="1"/>
    <property name="money" value="100.5"/>
</bean>

在使用 set 方法注入时,需要使用 property 标签,该标签属性如下:

  • name:指定注入时调用的 set 方法名称。(注:不包括 set 这三个字母,druid 连接池指定属性名称)
  • value:指定注入的数据。它支持基本类型和 String 类型。
  • ref:指定注入的数据。它支持其他 bean 类型。写的是其他 bean 的唯一标识。

4、复杂数据类型注入

首先,解释一下复杂类型数据,它指的是集合类型数据。
集合分为两类,一类是 List 结构(数组结构),一类是 Map 接口(键值对)。

private String[] myArray;
private Map<String, String> myMap;
private Set<String> mySet;
private Properties myProperties;

public void setMyArray(String[] myArray) {
    this.myArray = myArray;
}
public void setMyMap(Map<String, String> myMap) {
    this.myMap = myMap;
}
public void setMySet(Set<String> mySet) {
    this.mySet = mySet;
}
public void setMyProperties(Properties myProperties) {
    this.myProperties = myProperties;
}
<!-- bean 内部,set注入,注入复杂数据类型 -->
<property name="myArray">
    <array>
        <value>array1</value>
        <value>array2</value>
        <value>array3</value>
    </array>
</property>
<property name="myMap">
    <map>
        <entry key="key1" value="value1"/>
        <entry key="key2" value="value2"/>
    </map>
</property>
<property name="mySet">
    <set>
        <value>set1</value>
        <value>set2</value>
    </set>
</property>
<property name="myProperties">
    <props>
        <prop key="prop1">value1</prop>
        <prop key="prop2">value2</prop>
    </props>
</property>
  1. 在 List 结构的集合数据注入时,arraylistset 这三个标签通用,另外注值的 value 标签内部可以直接写值,也可以使用 bean 标签配置一个对象,或者用 ref 标签引用一个已经配合的 bean 的唯一标识。
  2. 在 Map 结构的集合数据注入时,map 标签使用 entry 子标签实现数据注入,entry 标签可以使用 keyvalue 属性指定存入 map 中的数据。使用 value-ref 属性指定已经配置好的 bean 的引用。同时 entry 标签中也可以使用 ref 标签,但是不能使用 bean 标签。而 property 标签中不能使用 ref 或者 bean 标签引用对象。

文章内容输出来源:拉勾教育Java高薪训练营;

上一篇:Delphi百度人脸搜索【支持人脸搜索、人脸库新增修改删除查询 】


下一篇:C# 之委托的多播