7. 实现Bean对象的初始化和销毁方法
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-method、destroy-method两个注解,在配置文件加载的过程中,把注解配置一并定义到
BeanDefinition 的属性当中。这样在initializeBean初始化操作的工程中,就可以通过反射的方式来调用配置在 Bean
定义属性当中的方法信息了。另外如果是接口实现的方式,那么直接可以通过 Bean 对象调用对应接口定义的方法即可,((
InitializingBean) bean).afterPropertiesSet(),两种方式达到的效果是一样的。 - 在 Bean 对象实例化过程中,需要在初始化前后执行一些额外的操作,那么就需要定义接口:
InitializingBean、DisposableBean,并在
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 新增加了两个属性:
initMethodName、destroyMethodName,这两个属性是为了在 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对象,已经被赋予了各种扩展能力。