Spring IOC容器(控制反转和依赖注入)
Java知识点总结:想看的可以从这里进入
目录
- 6、IoC容器
- 6.1、介绍
- 6.2、原理和实现
- 6.2.1、BeanFactory
- 6.2.2、ApplicationContext
- 6.3、Bean的管理
- 6.3.1、XML文件管理
- 6.3.2、注解管理
- 6.3.3、bean的作用域
6、IoC容器
6.1、介绍
在创建Spring项目时,我们会发现,通过XML文件设置对象后,不需要我们使用 new 主动创建对象,而是变成从Spring中获取对象,而管理这些对象的容器就是IOC。
IOC是 Inversion of Control 的缩写,我们称为“控制反转”。它于1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。IOC理论提出的观点大体是:借助于“第三方”实现具有依赖关系的对象之间的解耦。
至于为什么要解耦合,其实想想我们平时带的机械手表就知道了,机械手表是由很多精密的齿轮等耦合在一起实现的,即便是其中一个很小的齿轮出现了错误,就会导致整个手表运转失误。所以我们理想的系统才需要解耦合,就是为了不至于因为其中某个小失误,导致整个系统崩溃,而且解耦的系统也方便我们排查错误进行修改。
我们的Spring就是第三方,它通过IOC容器,使用各个Object完成互相之间解耦,这样的话,当你在实现o1的时候,根本无须再去考虑2、3、4了,它使对象之间的耦合程度尽可能达到了一种较低的水平。(在此之前我们要使用o1,需要同时把o2,o3,o4都创建一遍)
控制反转具体是什么?举个简单的例子:我们想喝一杯果汁方法有两个
- 自己准备材料、准备榨汁机,自己动手获取一杯饮料(制造果汁的控制权完全在自己手中,想喝只能自己买材料、自己动手制作)。
- 去饮品店购买,可以通过外卖、自己去买等多种方式(制造果汁的控制权在饮品店手中,我们只负责去买,至于怎么制作那就是饮品店自己的事了)。
以往的面向对象编程中,我们想在一个类中调用另一个类的对象和方法,需要使用 new 主动创建对象,以实现属性方法的调用,此时对象的控制权是在我们手中。但是控制反转就是将控制权交由第三方(IoC容器),通过该IoC容器根据描述信息去找寻使用者需要的资源,然后控制Java对象的实例化和初始化,管理对象和对象之间的依赖关系,这种控制权的转变就是控制反转的含义。其中IOC容器管理的java对象称为SpringBean。
2004年,Martin Fowler探讨了一个问题:既然IOC是控制反转,那么到底是哪些方面的控制被反转了呢?
经过详细地分析和论证后,他得出了答案:获得依赖对象的过程被反转了,它由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。
所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
Spring本质是一个生产管理Bean的第三方工厂,它按我们的需要生产管理Bean(第三方IOC容器通过我们的描述(XML、注解等),获取生产特定的对象Bean,并进行管理),所以控制反转是一种编程的思想,其中依赖注入是其解决Bean之间依赖的一种技术。而Spring IOC实现的核心就是反射机制。学习这里时可以了解一下工厂模式。
IoC大大降低了对象之间的耦合,开发中甚至我们可以不用去理解,仅仅知道怎么使用就可以(但为了提升业务水平,还是需要从源头分析学习的)。
6.2、原理和实现
在 Java 软件开发过程中,系统中的各个对象之间、各个模块之间、软件系统和硬件系统之间,或多或少都存在一定的耦合关系,IOC就是通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度。
它通过读取我们的xml文件中的配置,根据id标识获取Bean的全限定名,通过反射机制创建Bean对象,通过set方法注入值,然后通过getBean方法获取相应的对象。
而Spring是通过 BeanDefinition 这样一个对象来描述它所管理的所有的Bean以及对象间的依赖关系,它将读取的Bean的各种信息统一都封装成一个个的 BeanDefinition 对象
,这样就弱化了对Bean的定义,无论是通过什么方式获取的Bean对象,最终都是封装成 BeanDefinition 注册到IOC容器中,这样呢,IOC就不必关注我们各种各样的类和对象了,只需要统一操作BeanDefinition 即可,在降低耦合程度上,还增加了扩展性和灵活性。依赖反转功能都是围绕这个BeanDefinition的处理来完成的。
IOC容器的底层最核心的就是两个 Bean 工厂 接口:BeanFactory、ApplicationContext
。IOC就是基于这两个接口来设计的
6.2.1、BeanFactory
是Spring中最顶层的的 factory接口(org.springframework.beans.factory.BeanFactory),采用了Java经典的工厂名模式,它也是最简单的IOC容器,它定义了IOC的基本规范,在 BeanFactory 的基础上 Spring 通过继承逐层扩充容器的能力来实现一个完整的IOC。
BeanFacotry是Spring 内部的使用接口,不提供给开发人员进行使用
。这种方式采用了懒加载,容器在启动后加载配置文件时并不会马上创建对象,而是在程序中获取使用的时候才进行创建所需对象。
基于BeanFactory设计的层次结构,BeanFactory定义了基本的IoC容器的规范(如getBean可以获取Bean对象等),其下三个子接口:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。
HierarchicalBeanFactory接口增加了getParentBeanFactory(),使BeanFactory具备了双亲IoC容器的管理功能
- 其子接口ConfigurableBeanFactory定义了一些对BeanFactory的配置功能(比如通过setParentBeanFactory()设置双亲IoC容器,通过addBeanPostProcessor()配置Bean后置处理器等等)。
- ListableBeanFactory 接口表示这些 Bean 是可列的
- AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。
DefaultListableBeanFactory是BeanFactory层次中的最终实现,是一个简单IoC容器的实现。像其他IoC容器比如XmlBeanFactory等等,都是在DefaultListableBeanFactory的基础上做扩展。
它内部定义了一些基础方法
1、Object getBean(String name):通过Bean的对象名获取其实例(如果ioc有两个一样bean,那么在获取会出错)可以通过类型:类.class 获取
可以通过bean标签中设置的id值获取
可以通过 id+类型 获取
2、boolean containsBean(String name):查看bean是否存在
3、boolean isSingleton(String name):是否是单例模式
4、boolean isPrototype(String name):是否是原型模式
5、boolean isTypeMatch(String name, ResolvableType typeToMatch):查看一个bean对象是typeToMatch类型的
6、String[] getAliases(String name):返回bean 的别名(bean标签内name属性设置的名称)
7、Class<?> getType(String name):返回 FactoryBean 创建的对象类型
BeanFactory和FactoryBean:
- BeanFactory是IOC容器
FactoryBean是一个工厂Bean,可以生成某一个类型 Bean 的实例,可以让我们自定义 Bean 的创建过程。它是IOC中一个具有特色的工厂Bean。
Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
6.2.2、ApplicationContext
因为原始的BeanFactory的功能很简单,很多技术和插件无法支持,所以衍生出了ApplicationContext 接口,它是BeanFactory的子接口,包含了BeanFactory的所有功能,并在其基础上进行了扩展,增加了许多面向框架的特性,同时对应用环境做了许多适配。
- 支持信息源,可以实现国际化。(MessageSource接口)
- 访问资源。(ResourcePatternResolver接口)
- 支持应用事件。(ApplicationEventPublisher)
- 在ApplicationContext中提供的附加服务
它采用的策略是立即加载,即在Spring容器启动,加载配置文件后,就立即创建对象。因为使用Spring框架一般都会整合其他框架,所以把这些耗时耗内存的都在项目启动的时候进行处理更加合适,所以一般开发人员使用 ApplicationContext接口。
ApplicationContext有几个常用的实现类:(根据不同的配置方式使用不同的类来实例化)
- 子类ClassPathXmlApplicationContext(“xml文件”):从类路径ClassPath中加载指定的 XML 配置文件
- 子类FileSystemXmlApplicationContext(“xml文件”):加载磁盘路径下的XML配置文件
- 子类AnnotationConfigApplicationContext(类.class):用于读取(@Configuration)修饰的启动类
- 子类XmlWebApplicationContext:从web中获取XML配置,默认情况下,配置将从“/WEB-INF/applicationContext.xml”获取根上下文,从“/WEB-INF/test-servlet.xml”获取具有命名空间“test-servlet”的上下
6.3、Bean的管理
IOC通常通过三种方式来管理Bean对象
- 基于xml配置文件的方式实现
- 在Java接口和类中实现配置(通过注解 @Beam)
- 隐式的Bean的发现机制和自动装配
这几种方式应该遵循约定优于配置的原则,优先选择通过 隐式的Bean的发现机制和自动装配,其次选择在Java接口和类中实现配置,最后选择XML中配置。实际使用时是以三者混合使用,但优先级不同。
6.3.1、XML文件管理
通过XML文件装配对象
6.3.2、注解管理
使用注解装配Bean
6.3.3、bean的作用域
默认情况下,所有的 Bean 都是单例的,也就是说在整个 Spring 应用中, Bean 的实例只有一个。我们可以在 bean 标签中添加 scope 属性来配置 Bean 的作用范围。
Spring 5 共提供了 6 种 scope 作用域:
singleton:默认值,单例模式
- 实例化个数:1
- 实例化机制:创建容器时创建(默认使用ApplicationContext),存储在高速缓存中
生命周期:
- 创建:应用加载,创建容器,读取配置文件,对象直接创建
- 运行:只要容器在,对象就一直存在
- 销毁:当应用卸载时,销毁容器,对象随之销毁
prototype:原型模式
- 实例化个数:多个
- 实例化机制:只有每次注入或者获取Bean时,才会创建对象
生命周期:
- 创建:当使用对象时,对象创建
- 运行:只要对象在使用,就一直存活
- 销毁:对象一定时间内不使用,被java的垃圾回收期回收。
request
- 实例化机制:每次请求都会创建一次
生命周期
- 创建:每次Http请求,使用对象时,对象创建
- 运行:和Http请求中的request对象相同
- 销毁:处理完请求后销毁
session:只能在web开发中使用
- 实例化机制:在一次会话期内创建一次
生命周期
- 创建:每一个会话期,使用对象时,对象创建
- 运行:和一次session相同
- 销毁:随session销毁而销毁
还没有评论,来说两句吧...