IOC(Inversionof Control)控制反转:所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
DI(Dependency Injection)依赖注入:就是指对象是被动接受依赖类而不是自己主动去找,换句话说 就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。
谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
综上:IOC分为两个部分。
第一部分初始化一个IOC容器,获取外部资源文件(管理类 Bean 定义的相关数据)
第二部分IOC 容器对所管理的 Bean 进行依赖注入
1. BeanFactory(IOC容器管理Bean)
BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
最终的默认实现类是DefaultListableBeanFactory,他实现了所有的接口;
BeanFactory提供了管理bean的核心方法
2. BeanDefinition
SpringIOC 容器管理了我们定义的各种 Bean 对象及其相互的关系,Bean 对象在 Spring 实现中是以 BeanDefinition 来描述的。
BeanDefinition定义了Bean的数据结构,用来存储Bean。
Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:
3.ApplicationContext
ApplicationContext实现了最顶层的BeanFactory接口,也是一个IOC容器,ApplicationContext作为Spring的启动入口,也是IOC容器初始化的入口
ApplicationContext体系
IOC 容器的初始化包括BeanDefinition 的 Resource 定位、载入和注册这三个基本的过程
1.super(parent)方法 设置 Spring 的资源加载器
private final ResourceLoader resourceLoader;
2.setConfigLocations() 把配置文件路径存放到数组中(可传入多个参数路径)
private String[] configLocations;
3.refresh() 把所有的Bean重新构造一遍
4.obtainFreshBeanFactory() Bean 定义资源文件的载入(从这个方法开始)
5.refreshBeanFactory() 使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器refreshBeanFactory()方法,
子类refreshBeanFactory()
判断 BeanFactory 是否存在,如果存在则先销毁 beans 并关闭 beanFactory,接着
创建 DefaultListableBeanFactory,并调用 loadBeanDefinitions(beanFactory)装载 bean 定义。
5.1.createBeanFactory() 用createBeanFactory对beanFactory工厂初始化 newDefaultListableBeanFactory(getInternalParentBeanFactory())表示所有Bean都是由DefaultBeanFactory()创建.
DefaultBeanFactory的类结构图
6.loadBeanDefinitions(beanFactory) 调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
6.1.newXmlBeanDefinitionReader(beanFactory) 创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源
7.loadBeanDefinitions(beanDefinitionReader) 传入新建的读取器 Bean读取器真正实现加载的方法
7.1.getConfigResources(); 获取Bean定义资源的定位 即2中保存的参数String[] configLocations;
8.reader.loadBeanDefinitions(configLocations); XmlBean读取器调用其父类AbstractBeanDefinitionReader读取定位的Bean定义资源
9.loadBeanDefinitions(location) 是一个重载方法
11.loadBeanDefinitions(resources) 委派设计模式委派给XmlBeanDefinitionReader实现
12.doLoadBeanDefinitions()(重载方法) 将读入的XML资源进行特殊编码处理 载入XML形式Bean定义资源文件方法
首先/将资源文件转为InputStream的IO流 在从InputStream中得到XML的解析源
13.doLoadBeanDefinitions()(重载方法) 从特定XML文件中实际载入Bean定义资源的方法
14.doLoadDocument() 将XML文件转换为DOM对象,解析过程由documentLoader实现
15.registerBeanDefinitions() 这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构
16.documentReader.registerBeanDefinitions 解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口, 具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成
17.doRegisterBeanDefinitions(root) do开头的都是干活的方法,开始解析Bean
18.preProcessXml(root) 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
19.parseBeanDefinitions() 进入了加载过程 解析过程解析Bean.xml中的标签 ,把xml中的内容变成BeanDefinition 运用 delegate委派模式
22.BeanDefinitionReaderUtils.registerBeanDefinition() 向Spring IOC容器注册解析得到的Bean定义,这是Bean定义向IOC容器注册的入口 进入注册环节
Key就是Bean id value为BeanDefinition
总体流成:首先把需要加载的Bean.xml路径存放到数组中,在创建一个DefaultListableBeanFactory()容器,获取路径把路径下的XML文件转化成java文件,把java文件解析成BeanDefinition,在把BeanDefinition存储到ConcurrentHashMap中。