7. 实现Bean对象的初始化和销毁方法

工程结构

lqf-spring-step-07
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── BeanFactory.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       └── ClassPathXmlApplicationContext.java
│   │           ├── core
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           └── util
│   │               └── ClassUtils.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           ├── UserDao.java
    │           ├── UserService.java
    │           └── common
    │               ├── MyBeanFactoryPostProcessor.java
    │               └── MyBeanPostProcessor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

Spring 应用上下文和对Bean对象扩展机制的类关系,如图:

  • 以上整个类图结构描述出来的就是本次新增 Bean 实例化过程中的初始化方法和销毁方法。
  • 因为一共实现了两种方式的初始化和销毁方法,xml配置和定义接口,所以这里既有 InitializingBean、DisposableBean
    也有需要XmlBeanDefinitionReader 加载 spring.xml 配置信息到 BeanDefinition 中。
  • 另外接口 ConfigurableBeanFactory 定义了 destroySingletons 销毁方法,并由 AbstractBeanFactory 继承的父类
    DefaultSingletonBeanRegistry 实现 ConfigurableBeanFactory 接口定义的 destroySingletons 方法。
  • 最后就是关于向虚拟机注册钩子,保证在虚拟机关闭之前,执行销毁操作。
    • Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));

设计

可能面对像 Spring 这样庞大的框架,对外暴露的接口定义使用或者xml配置,完成的一系列扩展性操作,都让 Spring 框架看上去很神秘。其实对于这样在
Bean 容器初始化过程中额外添加的处理操作,无非就是预先执行了一个定义好的接口方法或者是反射调用类中xml中配置的方法,最终你只要按照接口定义实现,就会有
Spring 容器在处理的过程中进行调用而已。整体设计结构如下图:

  • 在 spring.xml 配置中添加 init-methoddestroy-method 两个注解,在配置文件加载的过程中,把注解配置一并定义到
    BeanDefinition 的属性当中。这样在 initializeBean 初始化操作的工程中,就可以通过反射的方式来调用配置在 Bean
    定义属性当中的方法信息了。另外如果是接口实现的方式,那么直接可以通过 Bean 对象调用对应接口定义的方法即可,((
    InitializingBean) bean).afterPropertiesSet(),两种方式达到的效果是一样的。
  • 在 Bean 对象实例化过程中,需要在初始化前后执行一些额外的操作,那么就需要定义接口:InitializingBeanDisposableBean,并在
    Bean对象实例化前后执行接口方法。

实现

定义初始化和销毁方法的接口

源码1: lqf.springframework.beans.factory.InitializingBean
源码2: lqf.springframework.beans.factory.DisposableBean

  • InitializingBean、DisposableBean,两个接口方法还是比较常用的,在一些需要结合 Spring
    实现的组件中,经常会使用这两个方法来做一些参数的初始化和销毁操作。比如接口暴漏、数据库数据读取、配置文件加载等等。

Bean属性定义新增初始化和销毁

源码1: lqf.springframework.beans.factory.config.BeanDefinition

  • 在 BeanDefinition 新增加了两个属性:initMethodNamedestroyMethodName,这两个属性是为了在 spring.xml 配置的 Bean
    对象中,可以配置init-method="initDataMethod" destroy-method="destroyDataMethod" 操作,最终实现接口的效果是一样的

源码2: lqf.springframework.beans.factory.xml.XmlBeanDefinitionReader

  • Bean属性定义增加初始化和销毁后,还需要在XmlBeanDefinitionReader类中,增加对新增属性的读取,并添加到BeanDefinition中

执行 Bean 对象的初始化方法

源码: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean

  • 抽象类 AbstractAutowireCapableBeanFactory 中的 createBean 是用来创建 Bean 对象的方法,在这个方法中之前已经扩展了
    BeanFactoryPostProcessor、BeanPostProcessor 操作,这里我们继续完善执行 Bean 对象的初始化方法的处理动作。
  • 在方法 invokeInitMethods 中,主要分为两块来执行实现了 InitializingBean 接口的操作,处理 afterPropertiesSet
    方法。另外一个是判断配置信息 init-method 是否存在,执行反射调用 initMethod.invoke(bean)。这两种方式都可以在 Bean
    对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。

定义销毁方法适配器(接口和配置)

源码: lqf.springframework.beans.factory.support.DisposableBeanAdapter

  • 目前有实现接口 DisposableBean配置信息 destroy-method,两种方式。而这两种方式的销毁动作是由
    AbstractApplicationContext
    在注册虚拟机钩子后看,虚拟机关闭前执行的操作动作。
  • 在销毁执行时不太希望还得关注都销毁那些类型的方法,它的使用上更希望是有一个统一的接口进行销毁,所以这里就新增了适配类,做统一处理。

创建Bean时注册销毁方法对象

源码: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary

  • 在创建 Bean 对象的实例的时候,需要把销毁方法保存起来,方便后续执行销毁动作进行调用。
  • 那么这个销毁方法的具体方法信息,会被注册到 DefaultSingletonBeanRegistry
    中新增加的 Map<String, DisposableBean> disposableBeans 属性中去,因为这个接口的方法最终可以被类
    AbstractApplicationContext 的 close 方法通过 getBeanFactory().destroySingletons() 调用。
  • 在注册销毁方法的时候,会根据是接口类型和配置类型统一交给 DisposableBeanAdapter 销毁适配器类来做统一处理

虚拟机关闭钩子注册调用销毁方法

源码1: lqf.springframework.context.ConfigurableApplicationContext
源码2: lqf.springframework.context.support.AbstractApplicationContext

  • 在 ConfigurableApplicationContext 接口中定义了一个方法:registerShutdownHook(),这个方法是用于注册虚拟机关闭钩子的。

总结

  • 主要完成了关于初始和销毁在使用接口定义 implements InitializingBean, DisposableBean
    和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod"
    的两种具体在 AbstractAutowireCapableBeanFactory 完成初始方法和AbstractApplicationContext 处理销毁动作的具体实现过程。
  • 可以看到目前这个 Spring 框架对 Bean 的操作越来越完善了,可扩展性也不断的增强。你既可以在Bean注册完成实例化前进行
    BeanFactoryPostProcessor 操作,也可以在Bean实例化过程中执行前置和后置操作,现在又可以执行Bean的初始化方法和销毁方法。
    所以一个简单的Bean对象,已经被赋予了各种扩展能力。