【Spring IOC容器学习笔记】一——什么是Spring IOC容器,它是怎么工作的
摘要
Spring IOC容器是Spring的核心功能,它构成了Spring框架的骨骼结构,没有它就没有上层MVC、AOP等高级特性。这节的学习笔记主要回答下面几个问题:
- Spring IOC容器是用来做什么的?
- 什么是bean?
- Spring IOC容器是如何工作的?
- Spring IOC容器与BeanFactory和ApplicationContext的关系是什么?
1 Spring IOC容器与bean
1.1 什么是Spring IOC 容器
把Spring IOC 容器看做一个黑盒,它的功能就是根据读取的配置元数据,将应用中的业务对象(POJOs)实例化后建立互相之间的依赖关系,提供给我们一个可使用的系统。
1.2 什么是bean
每个业务对象,经过容器的实例化得到的就是bean。bean被容器管理相互间的依赖关系,组成应用。在我的另一篇学习笔记里有bean的详细介绍,这里就不展开了。
1.3 怎么理解IOC
IOC是Inverse of Controll的简写,翻译为控制反转,指的是被实例化的对象对依赖创建的控制权从自身转移到容器。IOC的概念比较晦涩,我们可以借助依赖注入(Dependency Injection,DI)的概念辅助理解它。依赖注入的过程是指,POJO被容器实例化后,由容器负责将它的依赖准备好供使用。关于依赖的更详细说明可以看另外一篇学习笔记。
IOC技术与直接通过new 方法创建依赖相比有什么优点?
- 代码更加简洁
- 实现了依赖的创建和使用的解耦(使用依赖的类不用再关心去哪里找依赖去创建)
- 更容易进行单元测试
2 Spring IOC容器工作原理
这部分,我们进入Spring IOC 内部,看它由哪些组件构成,是怎么工作的。
容器中的每一个bean都会有一个对应的BeanDefinition
实例,该实例负责保存bean对象的所有必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等。当客户端向容器请求相应对象时,容器就会通过这些信息准备一个完整可用的bean实例返回给客户端。BeanDefinitionRegistry
抽象了bean的注册逻辑,包含registerBeanDefinition()、removeBeanDefinition()、getBeanDefinition()等注册管理BeanDefinition的方法。BeanFactory
抽象了bean的管理逻辑,包含getBean、containBean、getType、getAliases等管理bean的方法。
他们的关系如下图:
Spring IOC 容器的工作流程大致分为两个阶段:
阶段1:容器启动
容器在这阶段的主要工作是收集bean信息,也会进行一些验证性和辅助性的工作。容器要加载Configuration Meta信息,除了纯java代码实现配置的情况,其他方式如通过XML文件的读取,需要借助BeanDefinitionReader
组件进行解析。BeanDefinitionReader读取和分析Configuration Meta信息后,组装信息为bean对应的BeanDefinition,并把它注册到BeanDefinitonRegistry中,就完成了容器启动。示例代码:
// 通常为BeanDefinitionRegistry的实现类,这里以DeFaultListabeBeanFactory为例
BeanDefinitionRegistry beanRegistry = new DefaultListableBeanFactory();
// XmlBeanDefinitionReader实现了BeanDefinitionReader接口,用于解析XML文件
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReaderImpl(beanRegistry);
// 加载配置文件
beanDefinitionReader.loadBeanDefinitions("classpath:spring-bean.xml");
阶段2:实例加载
经过阶段1后,当某个请求通过容器的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发阶段2的工作:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。
// 从容器中获取bean实例
BeanFactory container = (BeanFactory)beanRegistry;
Business business = (Business)container.getBean("beanName");
3 BeanFactory和ApplicationContext
BeanFactory
可以管理任何对象,它是Spring IOC容器一种简单的实现,提供了最基本的依赖注入(DI)支持。而在实际场景下,我们更多的使用另外一种类型的容器:ApplicationContext
,它集成自BeanFactory,除了基本DI功能,还提供了更高级的功能,如事件监听。
两者bean实例加载策略有区别:BeanFactory默认是延迟加载策略,即只有当访问容器中的某个对象时,才对该对象进行实例化和依赖注入操作;ApplicationContext则模式在容器启动时就全部完成实例化和依赖注入操作。
总结
对使用者来说,可以把spring 容器看做一个生产工厂,它提前根据生产说明(Configuration Meta)把物料(POJOs)加工成产品(beans),使用者只要报出需要的产品名字(beanName)就可以得到提前生产好的产品,整体是简单工厂模式的体现。
容器的实现可以是简单的BeanFactory
或更高级的ApplicationContext
。它们借助BeanDefiniton
组件实现对bean及依赖信息的管理, 容器启动时收集所有bean的信息。当实例化bean的时候,容器负责将其依赖对象也进行实例化以供使用,这个过程就是依赖注入。
参考资料
1,给你一份Spring Boot知识清单
2,Spring Core Technologies
还没有评论,来说两句吧...