spring 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

 应用上下文容器的父接口

在这里插入图片描述
红色线路从接口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的继承体系

在这里插入图片描述

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

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

public FileSystemXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

/**

  • 应用文件系统中Resource的实现,通过构造FileSystemResource来获得一个在文件系统中定位的BeanDefinition
  • getResourceByPath是在BeanDefinitionReader读取器的loadBeanDefinition中被调用的
  • loadBeanDefinition采用了模板模式,具体的定位实现实际上由各个子类来完成,后面还会有许多这样的模板设计模式,
    */
    @Override
    protected Resource getResourceByPath(String path) {
    if (path.startsWith("/")) {
    path = path.substring(1);
    }
    return new FileSystemResource(path);
    }

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

在这里插入图片描述

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

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

根据调用栈进入源码

AbstractApplicationContext——refresh()方法

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

在这里插入图片描述

进入obtainFreshBeanFactory()——调用了模板方法refreshBeanFactory();该方法由子类去实现,这里的实现类是 AbstractRefreshableApplicationContext类

在这里插入图片描述

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

实例化了XmlBeanDefinitionReader

在这里插入图片描述

具体实现:loadBeanDefinitions(XmlBeanDefinitionReader reader)

在这里插入图片描述

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

我们得出部分结论

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

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

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


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

进入reader.loadBeanDefinitions(configLocations);

在这里插入图片描述

loadBeanDefinitions(location)最后会通过resourceLoader.getResources(location)获得resource
再调用loadBeanDefinitions(resource);
在这里插入图片描述

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

在这里插入图片描述

DefaultResourceLoader默认使用ClassPathContextResource来获得resource

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值