天天看点

spring IOC原理——初始化——定位IOC初始化过程

IOC

IOC设计模式是企业应用开发中,解耦组件之间的复杂关系的利器,Spring IOC模块就是这个模式的一种实现,Spring IOC提供了一个基本的JAVABean容器,通过IOC模式管理依赖关系,并通过依赖注入和AOP切面增强为JAVABean这样的POJO对象赋予事务管理、生命周期管理等基本功能。

前言:主要记录IOC初始化过程的几个步骤,参考:SPRING技术内幕:深入解析SPRING架构与设计原理,多年前翻过的一本Spring原理书,里面讲的细节大部分都忘了,回溯一下,顺便做个记录,也好将来翻阅,对书中的IOC,AOP,WEB等都做详细的记录,此章节为Spring系列,会不断上传,篇幅原因,一章就讲一部分。先简单介绍一下IOC的几个底层接口,以及核心容器,主要讲解IOC容器初始化的定位部分

涉及核心接口

Resource

数据源接口,封装了InputStream,作用是为容器提供用户数据源的接口。通俗的讲,容器启动需要的配置文件或配置类在哪?
           

ResourceLoader

加载资源的策略接口
           

BeanDefinition

BeanDefinition是IOC容器体系中非常重要的核心数据结构,可以看成是对bean定义的抽象  
           

BeanDefinitionReader

用于将Resource装载入BeanDedintion中的解析器
           

BeanFactory

容器基类接口,所有IOC容器的父接口 
           

ApplicationContext

应用上下文容器的父接口
           
spring IOC原理——初始化——定位IOC初始化过程

红色线路从接口BeanFactory——HierarchicalBeanFactroy——ConfigurableBeanFactory主要设计路径

以ApplicationContext应用上下文接口为核心的接口设计,主要涉及几口

BeanFactory——ListableBeanFactory——ApplicationContext——WebApplicationContext / ConfigurableApplicationContext

常用的应用上下文基本上都是WebApplicationContext / ConfigurableApplicationContext实现在这个接口体系中

 ListableBeanFactory和HierarchicalBeanFactory两个接口,连接BeanFactory接口定义和ApplicationContext应用上下文的接口定义。

 ApplicationContext通过继承MessageSouree、ResourceLoader、ApplicationEvenPublisher接口,在BeanFactory简单容器的基础上添加了许多对高级容易的特性支持   
           

IOC初始化过程

定位

Resource定位过程,这里指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口完成,这个Resource对各种形式的BeanDefinition的使用提供了统一接口,如FileSystemResource、ClassPathResource。定位过程类似于容器寻找数据的过程,就像水桶装水先要找水。

BeanDefinition的Resource定位步骤:

以编程的方式使用DefaultListableBeanFactory,先要定义Resource来定位容器使用的BeanDefinition.

ClassPathResource resource=new ClassPathResource("beans.xml"); (找水)创建IOC配置文件的资源,
 
   DefaultListableBeanFactory factory = new DefaultListableBeanFactory();(桶)创建一个BeanFactory。
 
  (装水器)创建一个读取器,resource并不能直接被使用,必须通过BeanDefinitionReader来对这些信息进行处理。
   XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory); 
 
   reader.loadBeanDefinition(res);(装水)从定义好的资源位置读入配置信息
           

DefaultListableBeanFactory

是接口ConfigurableListableBeanFactory和BeanDefinitionRegistry的默认实现,是一个纯粹的容器,需要为它配置特定的读取器才能完成这些功能,适合用于定制IOC,可以理解为Spring容器中默认的对象工厂的实现,是一个比较全面的对象工厂。工厂中的Bean都是基于元数据定义的 bean 和通过post-processors扩展的bean。它的典型作用就是注册所有的bean通过读取bean的配置文件,这样就可以通过bean的命名方便快速访问bean,通过本地缓存表。

ApplicationContext

一般我们使用ApplicationContext容器,ApplicationContext通过继承MessageSouree、ResourceLoader、ApplicationEvenPublisher接口,在BeanFactory简单容器的基础上添加了许多对高级容易的特性支持,这个接口系统是以BeanFactory和ApplicationContext为核心的,而BeanFactory又是IOC容器的最基本接口,在ApplicationContext的设计中,一方面,可以看到它集成了BeanFactory接口体系中的ListableBeanFactory、autowireCapableBeanFactory\HierarchicalBeanFactory等BeanFactory接口,具备了BeanFactory IOC容器的基本功能,另一方面通过继承MessageSource\ResourceLoader\ApplicationEventPublisher这些几口,BeanFactory为ApplicationContext赋予了更高级的IOC容器特性,为了再Web环境中使用它,还涉及了WebApplicationContext接口,而这个接口通过继承ThemeSource接口来扩充功能

先来看看三个常用的ApplicationContext实现类:

FileSystemXmlApplicationContext:从XML文件中载入Resource(配置文件)

ClassPathXmlApplicationContext:从类路径载入Resource(配置类)

XmlWebApplicationContext:从Web容器载入Resource(web项目)
           

我们主要以FileSystemXmlApplicationContext为例,讲述一下IOC容器中ApplicationContext系列的定位过程

先来看看FileSystemXmlApplicationContext的继承体系

spring IOC原理——初始化——定位IOC初始化过程

FileSystemXmlApplicationContext的具体实现,要走进源码,篇幅有限,只贴关键代码

//初始化过程中,调用refresh函数载入BeanDefinition,这个refresh启动了BeanDefinition的载入过程,它是容器启动的入口

public FileSystemXmlApplicationContext(

String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

throws BeansException {

super(parent);

setConfigLocations(configLocations);

if (refresh) {

refresh();

}

}

@Override

protected Resource getResourceByPath(String path) {

if (path.startsWith("/")) {

path = path.substring(1);

}

return new FileSystemResource(path);

}

我们来找找BeanDefinition的完整定位过程,首先查看调用栈

spring IOC原理——初始化——定位IOC初始化过程

清除看到BeanDefinition资源定位的过程,最初由refresh方法触发

那么,FileSystemXmlApplicationContext是在哪里BeanDefinitionReader的呢?

根据调用栈进入源码

AbstractApplicationContext——refresh()方法

详细描述了整个ApplicationContext的初始化过程,BeanFactory更新,MessageSource和PostProcessor注册,看起来更像是对ApplicationContext进行初始化的模板或执行提纲,为Bean的生命周期管理提供了条件

spring IOC原理——初始化——定位IOC初始化过程

进入obtainFreshBeanFactory()——调用了模板方法refreshBeanFactory();该方法由子类去实现,这里的实现类是 AbstractRefreshableApplicationContext类
           
spring IOC原理——初始化——定位IOC初始化过程

loadBeanDefinitions()方法是AbstractRefreshableApplicationContext类的抽象方法,由子类 AbstractXmlApplicationContext来实现

实例化了XmlBeanDefinitionReader

spring IOC原理——初始化——定位IOC初始化过程

具体实现:loadBeanDefinitions(XmlBeanDefinitionReader reader)

spring IOC原理——初始化——定位IOC初始化过程

看到具体的载入过程是委托给BeanDefinitionReader来完成的,因为这里的BranDefinition是通过XML文件定义,所以这里使用XmlBeanDefinitionReader 来载入BeanDefinition到容器中

我们得出部分结论

1: FileSystemXmlApplicationContext通过调用refresh()容器启动方法 其中实现了BeanDefinition的载入,

2:载入过程由XmlBeanDefinitionReader来完成,由于使用的是XML方式的定义,所以使用的是 XmlBeanDefinitionReader、如果使用了其他的BeanDefinition定义,则需要其他的BeanDefinitionReader实现类来完成

3:容器实际使用的IOC容器是标准容器DefultListableBeanFactory

而Resource载入在BeanDefinitionReader读入BeanDefinition时实现

进入reader.loadBeanDefinitions(configLocations);

spring IOC原理——初始化——定位IOC初始化过程

loadBeanDefinitions(location)最后会通过resourceLoader.getResources(location)获得resource

再调用loadBeanDefinitions(resource);

spring IOC原理——初始化——定位IOC初始化过程

其中getResources(location)为抽象方法,使用的类是DefaultResourceLoader()

spring IOC原理——初始化——定位IOC初始化过程

DefaultResourceLoader默认使用ClassPathContextResource来获得resource

再看看FileSystemXmlApplicationContext的集成路线上层继承了DefaultResourceLoader,重写了getResourceByPath(String path)方法,使用FileSystemResource返回Resource,在参数Resource中封装了对XML文件的I/O操作,所以读取器可以在打开I/O流后得到XML的文件对象。有了这个文件对象以后,将其解析为Document对象,再按照Spring的Bean定义规则来对XML的文档树进行解析,这个解析交给了BeanDefinitionParserDelegate来完成。

到此,ApplicationContext的resource定位流程就结束了,而后面的解析,注册,注入将在下一篇中具体讲解