Spring IOC和DI 详解

前言:这是一个系列,主要讲解Spring的核心部分,包括IOC、AOP等。这一部分讲解的是IOC和DI,内容如下。

这一篇包括的内容有:

  1. Spring核心概念
  2. IOC 和 DI 的案例;
  3. IOC的Bean详解;
  4. DI的几种注入方式;

Spring核心概念

Spring我们常讲的是它的两个核心,即IOC和AOP,这两个分别是什么意思呢?怎么体现的呢?这就是我们要学习的。所以我们主要学习四个方面:(1)IOC,(2)整合Mybatis(IOC的具体应用),(3)AOP,(4)声明式事务(AOP的具体应用)。

Spring家族

Spring其实是一个广泛的体系:

alt text

我们主要关注Spring Framework (Spring的核心)、Spring Boot、Spring Cloud
像什么SpringSecurity也会用到的。

Spring Framework4的体系如下:

alt text

IOC、IOC容器、DI、Bean

IOC、DI这一部分相当于是一种设计模式,一种设计思想,Spring实现了这种思想;

IOC:控制反转,原来我们创建对象都是直接new,而控制反转就是将创建对象的权利交给外部,由主动new产生对象转换为由外部提供对象。

IOC容器:Spring技术对IOC思想进行了实现,Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的”外部”。

Bean对象:IOC容器中放的就是一个个Bean对象。

DI:依赖注入,当IOC容器中创建好service和dao对象后,程序不能正常执行,因为service运行需要依赖dao对象,IOC容器中虽然有service和dao对象,但是service对象和dao对象没有任何关系,需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系,这就是依赖注入,一般有通过Setter方法注入,通过构造方法注入,自动装配。

最终效果:充分解耦,使用IOC容器管理bean(IOC),在IOC容器内将有依赖关系的bean进行关系绑定(DI),最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.

这种设计思想在于解耦,假如我们每个类都依赖一个接口,而该接口的实现类目前用的是类1,但是类1某一天不能满足需求了,我们需要将实现类都换成类2,这样子是不是要每个类中的接口实现类都要修改,而我们用IOC的方式,可以直接在配置文件中修改实现类为类2即可。

IOC 和 DI 的入门

需求分析:将BookServiceImpl和BookDaoImpl交给Spring管理,并从容器中获取对应的bean
对象进行方法调用。

IOC入门

  1. 创建Maven的java项目

alt text

  1. pom.xml添加Spring的依赖jar包

alt text

  1. 创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类

alt text

  1. resources下添加spring配置文件,并完成bean的配置

alt text

alt text

  1. 使用Spring提供的接口完成IOC容器的创建

alt text

  1. 从容器中获取对象进行方法调用

alt text

DI入门

DI就是将两个Bean连接在一起:

需求:基于IOC入门案例,在BookServiceImpl类中删除new对象的方式,使用Spring的DI完成
Dao层的注入

  1. 删除业务层中使用new的方式创建的dao对象

alt text

  1. 在业务层提供BookDao的setter方法

alt text

  1. 在配置文件中添加依赖注入的配置

alt text

alt text

这种其实是Setter注入的方法;

  1. 运行程序调用方法

alt text

IOC的Bean详解

Bean基础配置

基本配置 id 和 class

alt text

别名 name

alt text

alt text

配置了别名之后,在核心容器中可以通过别名来获取Bean

作用范围 scope 单例还是原型

alt text

bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象

bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高

如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,

因为所有请求线程共用一个bean对象,所以会存在线程安全问题。

如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,

因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。

表现层对象、业务层对象、数据层对象、工具对象适合交给容器管理,因为内部一般不会封装实例对象。

bean实例化

这一部分需要研究bean的三种实例化方法:构造方法,静态工厂和实例工厂。后面两种了解一下就行,主要是写一些框架的时候可能会用到。

1.构造方法实例化:这是默认的方法,Spring的核心容器通过类的构造方法实例化对象,会执行默认的构造方法。

2.静态工厂方式创建

alt text

alt text

将以上的静态工厂创造的方式替换为配置文件的方式,通过如下配置:

alt text

3.实例工厂方式创建(FactoryBean)

alt text

alt text

alt text

也可以通过Factory类来实现,这样配置类就可以少写一点了

alt text

1
2
3
4
5
6
7
T getObject() throws Exception;

Class<?> getObjectType();

default boolean isSingleton() {
return true;
}

bean生命周期

主要是bean从创建到销毁的过程:

  • 初始化容器
    1. 创建对象(内存分配)
    2. 执行构造方法
    3. 执行属性注入(set操作)
    4. 执行bean初始化方法
  • 使用bean
    1. 执行业务操作
  • 关闭/销毁容器
    1. 执行bean销毁方法

如何在bean的创建之后和销毁之前把我们需要添加的内容添加去,即bean的初始化和销毁方法,这边主要用到两种方式。

方式一

alt text

alt text

如何在JVM容器关闭之前先关闭IOC容器:

alt text

方式二

实现接口:

alt text

DI的几种注入方式;

Setter注入:

分为引用数据类型注入和简单数据类型注入。name是有讲究的,一般我们设置set方法就是将首字母大写然后设置,所以设置name的时候是将首字母小写去掉set。这有没有约定的味道呢?

需求:在bookServiceImpl对象中注入userDao

  1. 在BookServiceImpl中声明userDao属性,为userDao属性提供setter方法

alt text

  1. 在配置文件中使用property标签注入 ref

alt text

简单数据类型注入:value

alt text

构造函数注入:

需求:将BookServiceImpl类中的bookDao修改成使用构造器的方式注入。

  1. 将bookDao的setter方法删除掉,添加带有bookDao参数的构造方法。

alt text

  1. 在applicationContext.xml中配置

alt text

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

简单数据类型注入一样用value即可:

alt text

也可以通过type来设置:

alt text

alt text

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
  • 强制依赖指对象在创建的过程中必须要注入指定的参数
  1. 可选依赖使用setter注入进行,灵活性强
  • 可选依赖指对象在创建过程中注入的参数可有可无
  1. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相
    对严谨
  2. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选
    依赖的注入
  3. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注
  4. 自己开发的模块推荐使用setter注入

自动装配

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

自动装配的方式:

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

按类型:

alt text

需要注入属性的类中对应属性的setter方法不能省略

被注入的对象必须要被Spring的IOC容器管理

按照类型在Spring的IOC容器中如果找到多个对象,会报NoUniqueBeanDefinitionException

按名称:

alt text

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

集合注入

alt text

alt text

Properties是Java用来读取配置文件的一个类。