一、前言
这是我Spring专栏的第八篇文章: Spring之Bean生命周期源码分析(二), 主要讲解了获取Bean的销毁, 也是Bean生命周期内的最后一步. 在看本篇文章之前建议先看一下上篇文章当做前置学习 Spring之Bean生命周期源码分析(二)
Spring专栏全部内容如下:
- Spring中的IOC DI和AOP分别是什么
- Spring底层核心原理之bean创建流程有哪些
- Spring之事务
- Spring之手写模拟bean的创建流程
- Spring之概念和工作流程
- Spring之Bean生命周期源码分析(一)
- Spring之Bean生命周期源码分析(二)
二、记录有销毁方法的Bean
前置信息 - 设置Bean的销毁方法
如下图所示, 我们可以在Bean方法上实现 DisposableBean接口的 destory方法, 这个方法就是 Bean销毁时所执行的方法
在启动类执行相应的 close方法就会对 bean对象进行销毁
判断当前 Bean是否存在销毁方法
Bean的销毁方法在 AbstractBeanFactory.registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd)
我们直接去看if判断, 有一个 requiresDestruction(bean, mbd)方法, 这个方法就是去判断你的Bean有没有销毁方法
DisposableBeanAdapter.hasDestroyMethod方法
首先我们进入 DisposableBeanAdapter.hasDestroyMethod方法
在这个方法里, 我用红框圈了一个判断条件, 通过方法名称就可以判断出来他是判断这个 bean的实体类上是否有bean的销毁方法的, 我们点进去看一下
点进去之后可以看到, 它最开始就去判断我们的 bean实体类有没有去实现接口 DisposableBean或者 AutoCloseable, 如果实现了这两个接口, 那么直接返回true, 代表着这个 bean有销毁方法
如果没有实现, 那我们接着往下面走, 可以看到它执行了一个方法 inferDestroyMethodIfNecessary, 并将其返回, 该方法详情如下图所示:
该方法简单讲解:
- 通过 BeanDefinition取出指定的销毁方法名字
- 如果没有指定
- 在通过 BeanDefinition.getDestroyMethodName取一次
- 如果获取到的 destroyMethodName == inferred
- 就会去判断有没有实现 DisposableBean 接口
- 肯定是没有实现的, 之前就已经判断过了
- 获取当前 bean对应 类的close方法, 就把这个方法当做销毁方法
- 如果没有找到, 就去找 shutdown方法, 把这个方法当做销毁方法
- 最后就是两个三元运算符, 这个没什么好说的了
hasDestructionAwareBeanPostProcessors方法
这个方法就是判断当前 bean有没有销毁的逻辑
DisposableBeanAdapter.hasApplicableProcessors
调用所有的定义的销毁的 postProcessor
上图中的if判断有一个方法 processor.requiresDestrunction(bean) 是用来判断当前Bean的类有没有加上 @PreDestory注解, 如果有就返回 true, 就证明了, 是通过注解的方式实现了销毁方法
确定该 Bean对象有销毁方法后
确定该 Bean对象有销毁方法后就会进入下图这个判断
如果 BeanDefinition 对象是单例的
就会进入下面的方法
可以看到这个方法就是通过构造方法创建了一个 DisposableBeanAdapter实例,然后将这个实例和 beanName传进了 registerDisposableBean方法中, 我们看一下这个方法
可以看到, 最后就是这个beanName和创建的 DisposableBean放进了一个map中
如果 BeanDefinition对象不是单例的
如下图所示:
- 如果当前 BeanDefinition不是单例的
- 那么会取出当前 BeanDefinition的Scope类型
- 并执行对应的 registerDestructionCallback方法
和单例一样的是, 也是传递了一个 beanName和DisposableBean类的实例
但是点进这个方法内部可以看到, 他的内部实现和单例的情况不一样
三、Bean的销毁
关于Bean的销毁, 我们通过容器关闭执行的 close方法点进去
点击去可以看到一个 doClass()方法
doClass方法如下图所示:
在这个方法里面, 也有很多知识点,我们后续会讲到, 目前主要看的方法是 destroyBeans(), 点进这个方法
如上图所示, 我们可以通过这个方法名称看出来, 它销毁了我们 Bean工厂内所有的单例Bean
原型Bean Spring中都没有存储, 所以不用销毁
在往下走, 我们跳转到对应的方法
super.destroySingletons();
先看它执行了它父类的方法
查看是否有销毁的方法
我们可以看到, 他去遍历了一个map, 这个map就是之前我们在记录销毁方法时的 map
在这个方法中, 可以看到还是先移除掉单例池
下一步执行了以下代码, 将自己从map中移除掉
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); 复制代码
最后执行了 destroyBean方法
destroyBean方法
如下图所示, 这个map表示的是, 当前bean被哪些bean依赖了, 当前bean要销毁的话, 其他的bean也要被销毁
这个方法比较重要的是他最后执行了 destroy方法(销毁方法)
清空单例池
这一步就是他去遍历所有有销毁方法, 销毁逻辑的Bean, 加入没有销毁方法的Bean, 那么就执行下面的三个clear, 清空map
最后执行了一个方法, 清空了单例池
四、总结
到这里 Bean销毁的记录和执行就结束了, 下一篇文章开始讲解Spring依赖注入相关源码