Spring-1 IOC 和 DI 详解
Spring IOC和DI 详解
前言:这是一个系列,主要讲解Spring的核心部分,包括IOC、AOP等。这一部分讲解的是IOC和DI,内容如下。
这一篇包括的内容有:
- Spring核心概念
- IOC 和 DI 的案例;
- IOC的Bean详解;
- DI的几种注入方式;
Spring核心概念
Spring我们常讲的是它的两个核心,即IOC和AOP,这两个分别是什么意思呢?怎么体现的呢?这就是我们要学习的。所以我们主要学习四个方面:(1)IOC,(2)整合Mybatis(IOC的具体应用),(3)AOP,(4)声明式事务(AOP的具体应用)。
Spring家族
Spring其实是一个广泛的体系:
我们主要关注Spring Framework (Spring的核心)、Spring Boot、Spring Cloud
像什么SpringSecurity也会用到的。
Spring Framework4的体系如下:
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入门
- 创建Maven的java项目
- pom.xml添加Spring的依赖jar包
- 创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类
- resources下添加spring配置文件,并完成bean的配置
- 使用Spring提供的接口完成IOC容器的创建
- 从容器中获取对象进行方法调用
DI入门
DI就是将两个Bean连接在一起:
需求:基于IOC入门案例,在BookServiceImpl类中删除new对象的方式,使用Spring的DI完成
Dao层的注入
- 删除业务层中使用new的方式创建的dao对象
- 在业务层提供BookDao的setter方法
- 在配置文件中添加依赖注入的配置
这种其实是Setter注入的方法;
- 运行程序调用方法
IOC的Bean详解
Bean基础配置
基本配置 id 和 class
别名 name
配置了别名之后,在核心容器中可以通过别名来获取Bean
作用范围 scope 单例还是原型
bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高
如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,
因为所有请求线程共用一个bean对象,所以会存在线程安全问题。
如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,
因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。
表现层对象、业务层对象、数据层对象、工具对象适合交给容器管理,因为内部一般不会封装实例对象。
bean实例化
这一部分需要研究bean的三种实例化方法:构造方法,静态工厂和实例工厂。后面两种了解一下就行,主要是写一些框架的时候可能会用到。
1.构造方法实例化:这是默认的方法,Spring的核心容器通过类的构造方法实例化对象,会执行默认的构造方法。
2.静态工厂方式创建
将以上的静态工厂创造的方式替换为配置文件的方式,通过如下配置:
3.实例工厂方式创建(FactoryBean)
也可以通过Factory类来实现,这样配置类就可以少写一点了
1 | T getObject() throws Exception; |
bean生命周期
主要是bean从创建到销毁的过程:
- 初始化容器
- 创建对象(内存分配)
- 执行构造方法
- 执行属性注入(set操作)
- 执行bean初始化方法
- 使用bean
- 执行业务操作
- 关闭/销毁容器
- 执行bean销毁方法
如何在bean的创建之后和销毁之前把我们需要添加的内容添加去,即bean的初始化和销毁方法,这边主要用到两种方式。
方式一
如何在JVM容器关闭之前先关闭IOC容器:
方式二
实现接口:
DI的几种注入方式;
Setter注入:
分为引用数据类型注入和简单数据类型注入。name是有讲究的,一般我们设置set方法就是将首字母大写然后设置,所以设置name的时候是将首字母小写去掉set。这有没有约定的味道呢?
需求:在bookServiceImpl对象中注入userDao
- 在BookServiceImpl中声明userDao属性,为userDao属性提供setter方法
- 在配置文件中使用property标签注入 ref
简单数据类型注入:value
构造函数注入:
需求:将BookServiceImpl类中的bookDao修改成使用构造器的方式注入。
- 将bookDao的setter方法删除掉,添加带有bookDao参数的构造方法。
- 在applicationContext.xml中配置
name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
ref属性指向的是spring的IOC容器中其他bean对象。
简单数据类型注入一样用value即可:
也可以通过type来设置:
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 强制依赖指对象在创建的过程中必须要注入指定的参数
- 可选依赖使用setter注入进行,灵活性强
- 可选依赖指对象在创建过程中注入的参数可有可无
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相
对严谨 - 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选
依赖的注入 - 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注
入 - 自己开发的模块推荐使用setter注入
自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配的方式:
- 按类型(常用)
- 按名称
- 按构造方法
- 不启用自动装配
按类型:
需要注入属性的类中对应属性的setter方法不能省略
被注入的对象必须要被Spring的IOC容器管理
按照类型在Spring的IOC容器中如果找到多个对象,会报NoUniqueBeanDefinitionException
按名称:
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推
荐使用 - 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入
Properties是Java用来读取配置文件的一个类。