spring 系列之 IOC 容器结构
IOC 容器结构
IOC(控制反转): 传统 javaSE 程序设计,我们直接在对象内部通过 new 进行创建对象,是程序主动去创建依赖对象,而 Ioc 是有专门一个容器来创建这些对象,即由 Ioc 容器来控制对象的创建。
大家都知道 spring 的核心组件分别是 IOC 和 AOP 等,其中 IOC 是目前开发中用的最多也最熟悉的,那么 spring 是怎么实现 IOC 组件功能的呢?我们先从 IOC 容器的结构出发深入浅出的讲解 Spring 的 IOC 组件,由于 Spring 中的 IOC 功能实属很强大, 我会将这个作为一个系列去讲解 Spring 的 IOC 功能,当然,本人对 SpringIOC 功能也不是全知全会,只是将自己的一些浅薄的见解通过文章表现出来,如果有什么理解不对的地方,希望各位能在评论或者私信我。
IOC 容器组件概述
资源加载器(ResourceLoader):Spring 用于加载资源文件并生成 Resource 的对象的组件(可类比 jdk 中的 classloader)。
资源描述组件(Resouurce):Spring 对资源文件,如:xml、properties 等资源的描述
Bean 对象构建组件(BeanDefinitionReader):Spring 中将 Reource 转换生成 beanDefinition 对象的组件
Bean 描述组件(BeanDefinition):Spring 对 Bean 描述的基本数据结构
bean 注册器(BeanRegister):用于将所有 Bean 注册到 IOC 容器中的 BeanFactory 中的组件-bean 容器 (BeanFactory):Spring 容器,里面存放 Spring 所管理的所拥有的 bean 容器(Map)。
springIOC 容器的启动过程如下:
创建 Spring 容器,也就是 BeanFactory
Spring 容器通过 ResourceLoader+ResourceResolver 解析资源生成 Resource 对象
将生成的 Resource 对象通过 BeanDefinitionReader 转换成 BeanDefinition 对象
将生成的 BeanDefinition 对象通过 BeanRegister(AliasRegister、SingletonRegister)注册到容器中
容器初始化完成
这个过程就是对 Spring 源码 IOC 容器初始化的一个抽象理解,如果是不太清楚 SpringIOC 容器的源码的小伙伴可能会很陌生,对于这种对有看过 spring 源码的小伙伴,这里只需要你们有个粗略的印象就好,后面我会通过一个专栏去讲解这个 SpringIOC 容器的启动过程和 Bean 的创建过程,所以不要着急,先有个大概的印象,对之后我们去跑源码的时候会很有帮助。
IOC 容器组建详解
上面,我们已经对 SpringIOC 容器组件进行了一个粗略的了解,下面我们再对 SpringIOC 容器的各个组件的继承关系、具体功能做一个解释:
资源描述组件(Resource)
是 Spring 对资源描述的组件,是信息的一个载体,像各种类型的文件、二进制流都是资源,这里大家应该也能想到,Spring 使用过程中会使用很多资源,如 xml、properties 等,而 Resource 就是这些文件的一个载体,这个组件中有两个常用的类,如 FileSystemResource 表示文件系统上的资源,UrlResource 则是表示网络资源。
从 Resource 接口的继承关系,我们也能清楚的知道它就是对文件资源的一种描述。Resource 的类图中的 ServletContextResource 故名思义就是对 tonmcat 中的 ServletContext 资源的描述;ClassPathResource 表示的类加载路径上的资源;ByteArrayResource 表示的是字节数组资源。FileSystemResource 和 UrlResource 的含义,上面已经说过了。
资源加载组件(ResourceLoader+ResourceResolver)
这个组件其实有两个功能其中一个功能是负责相关资源的加载,大家可以类比一下类加载器,这个功能有 ResourceLoader 体系完成,还有一个功能是资源的解析,而资源的解析是通过 ResourceResolver(资源解析器)实现完成的。
而 spring 支持的几种加载的资源的方式有:
URL 位置资源,如“file:C:/application.txt”
ClassPath 位置资源,如“classpath:application.xml"(大家对这种资源加载应该是比较熟悉的)
相对路径资源,如“WEB-INF/application.xml”
而 spring 实现几种加载资源的方式其实就是通过策略模式所实现的,对于不同的方式加载资源采用不同的策略。而且返回的 Resource 对象也不同,这个过程也同样在源码中有体现。
下面这是 FileSystemResourceLoader 获取资源的策略,返回的 Resource 是继承了 FileSystemResource 的 FileSystemContextResource,同样的其他几种加载方式在源码中都是类似的结构,这里就不过多介绍了,之后 spring 系列的博客会有详细说明。
看下面类图,我们发现了,ResouceLoader 有两个继承分支,这两个分支分别代表着资源加载和资源解析两种功能。
BeanDefinitionReader(Bean 构造器组件)
将 Resouce 对象转换成 BeanDefinition 对象,就是将内部资源数据转换成 Spring Bean 描述数据。这种转换的模式在 Dom4j 解析器中也有体现。
上面这个图中,是不完全的,在最新的 spring 版本中还加了一个 GroovyBeanDefinitionReader,是用于构建 groovy 配置文件中的 Bean 信息的(这是一种新的定义 bean 的方式,个人觉得很少能用上,这里就不过多细说了,如果可以想了解的,可以去问度娘)。而 PropertiesBeanDefinitionReader 和 XmlBeanDefinitionReader 这两个类分别是构建.propertie 文件中的 bean 对象和构建 xml 文件中 bean 对象。
Bean 注册组件(BeanRegistry)
将 BeanDefinition 对象注册到 Bean 容器中。
spring 一共有 AliasRegistry 和 SingletonBeanRegistry 这两种体系,分别表示通过别名注册和单例注册,这两种注册在我们使用 spring 的时候应该深有体会。
Bean 容器组件(BeanFactory)
是整个 SpringIOC 的核心组件,其他组件都是为 Bean 容器组件服务,但又不单纯为其服务。这个组件中装着 Spring 容器所管理的所有的 Bean 对象以及所需要的各种数据。其中 BeanFactory 有很多文章说他是一个初级容器,是因为这个这个容器的功能很简单,就是装 Bean 对象,是一个纯粹的容器,而 ApplicationContext 这个容器不单纯是用于装 Bean,它还有着其他的功能,如 Bean 生命周期的管理等。
可以说 BeanFactory 是面向 spring 本身而言的,而 ApplicationContext 是面向用户而言的。
对于 ApplicationContext 它不仅继承了 BeanFactory 的功能还和应用环境有着藕断丝连的关系。因此的它被命名为应用上下文对象是非常的合适的。
ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其他的接口扩展了 BeanFactory 的功能。
ClassPathXmlApplicationContext:默认从类路径加载配置文件
FileSystemXmlApplicationContext:默认从文件系统中装载配置文件
ApplicationEventPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。实现了 ApplicationListener 事件监听接口的 Bean 可以接收到容器事件 , 并对事件进行响应处理 。 在 ApplicationContext 抽象实现类 AbstractApplicationContext 中,我们可以发现存在一个 ApplicationEventMulticaster,它负责保存所有监听器,以便在容器产生上下文事件时通知这些事件监听者
MessageSource:为应用提供 i18n 国际化消息访问的功能;
ResourcePatternResolver : 所 有 ApplicationContext 实现类都实现了类似于 PathMatchingResourcePatternResolver 的功能,可以通过带前缀的 Ant 风格的资源文件路径装载 Spring 的配置文件。
LifeCycle:该接口是 Spring 2.0 加入的,该接口提供了 start()和 stop()两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被 ApplicationContext 实现及具体 Bean 实现, ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以达到管理和控制 JMX、任务调度等目的
ConfigurableApplicationContext 扩展于 ApplicationContext,它新增加了两个主要的方法: refresh()和 close(),让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用 refresh()即可启动应用上下文,在已经启动的状态下,调用 refresh()则清除缓存并重新装载配置信息,而调用 close()则可关闭应用上下文。这些接口方法为容器的控制管理带来了便利,但作为开发者,我们并不需要过多关心这些方法。
版权声明: 本文为 InfoQ 作者【王威07325】的原创文章。
原文链接:【http://xie.infoq.cn/article/bb43017259487df8f24ac1616】。文章转载请联系作者。
评论