今天看啥  ›  专栏  ›  安东尼_Anthony

【笔记】Java Web 之Spring核心 之IoC

安东尼_Anthony  · 简书  ·  · 2017-12-21 21:51

Spring的核心是控制反转(IoC)和面向切面(AOP)。他们是Spring模块中其他组件模块和应用开发的基础。

Spring 中的 IOC容器

在Spring Ioc容器的设计中,有俩个主要的容器系列:一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器最基本的功能;另外一个是ApplicationContext应用上下文,他作为容器的高级形态而存在。

1 什么是Ioc 容器

IOC容器为开发者管理对象之间的依赖关系提供了很多便利和基础服务。

什么是IOC容器?它在Spring容器中到底长什么样?

对于IOC容器的使用者来说,我们经常接触到的BeanFactory和ApplicationContext都可以看成是容器的具体表现形式。如果深入到Spring的实现中去看,我们所说的IOC容器,实际上代表着一系列功能各异的容器产品,只是容器的功能有大有小,有各自的特点。

在这些Spring提供的基本的IOC容器的接口定义和实现的基础上,Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及他们之间的相互依赖关系。BeanDeifinition抽象了我们对于Bean的定义,是让容器起作用的主要数据类型。

IOC容器是用来管理对象依赖关系的,对IOC容器来说,BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构。

2 IOC容器的设计

下图描述了Spring  Ioc容器中的主要接口设计。

  • 2.1 从接口BeanFactory到HiearerchialBeanFactory,再到ConfigurableBeanFactory,是一条主要的BeanFactory设计路径。这条接口设计路径中,BeanFactory接口定义了基本的IOC容器规范。在这个接口定义中,BeanFactory包括了getBean()这样的IOc容器的基本方法(通过这个方法可以从容器中获取BEAN)。而HiearerchialBeanFactory接口在继承了BeanFactory的基本接口之后,增加了getParentBeanFactory()的接口功能,使得BeanFactory具备了双亲IOc容器的管理功能。ConfigurableBeanFactory主要定义了对BeanFactory的配置功能,比如setParentBeanFactory()设置双亲IOC容器,通过addBeanPostProcessor()配置Bean的后置处理器等。通过这些接口设计的叠加,定义了BeanFactory就是简单的IOC容器的基本功能。

  • 2.2 第二条设计主线是:以ApplicationContext应用上下文接口为核心的接口设计。这里涉及的主要设计接口有,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到常用的WebApplicationContext或者ConfigurableApplicationContext接口。项目中常用的应用上下文基本都是ConfigurableApplicationContext或者WebApplicationContext的实现。在这个接口体系中,ListableBeanFactory和HiearerchialBeanFactory俩个接口,连接BeanFactory接口定义和applicationContext应用上下文接口定义。ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了setBeanDefinitionNames接口方法;
    对于ApplicationContext接口,它通过继承了MessageSource、ResourceLoader、ApplicationEventPublisher接口,在BeanFactory简单Ioc容器的基础上添加了许多对高级容器的特性的支持。

  • 2.3 图中涉及的是主要的接口关系,而具体的Ioc容器都是在这个接口体系下实现的,比如DefaultListableBeanFactory,这个基本Ioc容器的实现就是实现了ConfigurableBeanFactory,从而成为了一个简单Ioc容器的实现。像其他的Ioc容器,比如XMLBeanFactory,都是在DefaultListableBeanFactory的基础上做扩展。同样,ApplicationContext的实现也是如此。

  • 2.4 这个接口系统是以BeanFactory和ApplicationContext为核心的,而BeanFactory又是Ioc容器的最基本的接口,在ApplicationContext的设计中,一方面,可以看到他继承了HiearerchialBeanFactory等BeanFactory的接口,具备了BeanFactory Ioc容器的基本功能,另外一方面,通过继承MessageSource、ResourceLoader、ApplicationEventPublisher这些接口,BeanFactory为ApplicationContext赋予了更高级的Ioc容器特性。对于ApplicationContext而言,为了在Web环境中使用它,还设计了WebApplicationContext接口,而这个接口通过继承ThemeSource接口来扩充功能。

3 IOC容器的初始化过程

简单来说IOC容器的初始化是通过refresh()方法来启动的,这个方法标志着IOC容器的正式启动。具体来说,这个启动包括BeanDefinition的Resource的定位、载入和注册三个基本过程。在分析之前,Spring把这三个过程分开,并使用不同的模块来完成,如使用相应的ResourceLoader、BeanDefinitionReader等模块,通过这样的设计方式,可以让用户更加灵活地对这三个过程进行裁剪和扩展,定义出最适合自己的IOC容器的初始化过程。

  • 3.1第一个过程Resource定位。这个Resource指的是BeanDefinition的资源定位,它由ResourceLoader统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一的接口。对于BeanDefinition的存在形式,比如在文件系统中的Bean定义信息可以使用FileSystemResource进行抽象;在类路径中的Bean定义信息可以使用ClassPathResource来使用。

  • 3.2 第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IOC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。具体来说。这个BeanDefinition实际上就是POJO对象在IOC容器中的抽象,通过这个BeanDefinition定义的数据结构,使IOC容器能够方便地对POJO对象也就是Bean进行管理。

  • 3.3 第三个过程是向IOC容器注册这些BeanDefinition的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程中把载入过程中解析到的BeanDefinition向IOC容器进行注册。通过分析,在IOC容器内部将BeanDefinition注入到一个HashMap中去,IOC容器就是通过这个HashMap来持有这些BeanDefinition数据的。

值得注意的是,这里谈的是IOC容器初始化过程,在这个过程中,一般不包含Bean依赖注入实现,在IOC设计中,Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。但有一个例外,在IOC容器时有一个预实例化的配置,通过这个预实例化的配置(可以通过bean定义信息的lazyinit,实际应用中也就是spring ioc配置文件的<bean lazyinit="true">这种配置),用户可以对容器初始化过程作一个微小的控制,从而改变这个被设置lazyinit属性的Bean的依赖注入过程。比如,如果我们对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在IOC容器初始化时就预先完成了,而不需要等到整个初始化完成以后,第一次使用getBean时才会触发。

4 IOC容器的依赖注入

在IoC容器初始化的过程中,并没有看到IoC容器对Bean依赖关系的注入。假设IoC容器已经载入了Bean信息,依赖注入的过程是用户第一次向IoC容器索要Bean时触发的,当然也有例外,也就是通过lazy-init属性让容器完成Bean的预初始化。预初始化也是一个完成依赖注入的过程,只不过它是在初始化的过程中完成的。在IoC容器接口BeanFactory中,有一个getBean的接口定义,这个接口的实现就是触发依赖注入发生的地方。

5 ApplicationContext和Bean的初始化和销毁

于BeanFactory,特别是ApplicationContext,容器自身也有一个初始化和销毁关闭的过程。下面详细看看在这两个过程中,应用上下文完成了什么,可以让我们更多地理解应用上下文的工作,容器初始化和关闭过程可以简要地通过下图表现。

从图中可以看到,对ApplicationContext启动的过程是在AbstractApplicationContext中实现的。在使用应用上下文时需要做一些准备工作,这些准备工作在prepareBeanFactory()方法中实现。在这个方法中,为容器配置了ClassLoader、PropertyEditor和BeanPost-Processor等,从而为容器的启动做好了必要的准备工作。

容器初始化和关闭过程

容器的实现是通过IoC管理Bean的生命周期来实现的。Spring IoC容器在对Bean的生命周期进行管理时提供了Bean生命周期各个时间点的回调。在分析Bean初始化和销毁过程的设计之前,简要介绍一下IoC容器中的Bean生命周期。

  • Bean实例的创建。

  • 为Bean实例设置属性。

  • 调用Bean的初始化方法。

  • 应用可以通过IoC容器使用Bean。

  • 当容器关闭时,调用Bean的销毁方法。

参考资料




原文地址:访问原文地址
快照地址: 访问文章快照