【转】spring bean 卸载
spring bean 卸载
起因:
群里的一个朋友问到: 关于配置destory-method, springboot中 yml如何指定
首先介绍 bean卸载的三种形式
自定义destory-method
实现 org.springframework.beans.factory.DisposableBean 或者 java.lang.AutoCloseable
@Bean 注解时,自动推断. 存在close() 或者 shutdown() 就调用
接下来看一个简单的卸载bean的例子
简单卸载示例
bean实体
public class MyDispose implements Closeable {
@Override
public void close() throws IOException {
System.out.println("MyDispose 执行关闭");
}
}
applicationContext.xml
<bean name="disposeBean" class="com.aya.mapper.model.MyDispose">
</bean>
测试类
@Test
public void testApplicationContextGetBean() {
ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
factory.close();
}
控制台输出:MyDispose 执行关闭
源码分析
接下来逆向分析,找到spring是如何卸载bean的
逆向-close
在 MyDispose.close() 断点
顺着调用堆栈一层一层往上找,直到 destroySingleton 部分
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
public void destroySingleton(String beanName) {
// Remove a registered singleton of the given name, if any.
removeSingleton(beanName);
// Destroy the corresponding DisposableBean instance.
DisposableBean disposableBean;
synchronized (this.disposableBeans) {
//集合移除对象,返回被移除的对象
disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
}
// 卸载移除的对象
destroyBean(beanName, disposableBean);
}
得出结论: this.disposableBeans.put 的地方就是注册卸载bean的地方,那里一定有条件判断
逆向-引用搜索
找到 this.disposableBeans 的定义private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
然后搜索 disposableBeans 的所有引用,找到disposableBeans.put 的代码区
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
接下来对 registerDisposableBean 断点,在按照同样的方式,栈针回溯
逆向-条件判断
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
// bean的 scope!=prototype && 必须是销毁的bean
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// 将 beanName 添加到 this.disposableBeans
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
接下来跟踪条件判断requiresDestruction,分析卸载的源头
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
protected boolean requiresDestruction(@Nullable Object bean, RootBeanDefinition mbd) {
return (bean != null &&
(DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}
分为3组条件
1. bean!=null
2. bean 有卸载方法
3. 有实现DestructionAwareBeanPostProcessor的bean 并且 方法DestructionAwareBeanPostProcessor.requiresDestruction(bean)的结果为true
bean的卸载方法
org.springframework.beans.factory.support.DisposableBeanAdapter
private static final String CLOSE_METHOD_NAME = "close";
private static final String SHUTDOWN_METHOD_NAME = "shutdown";
public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
//实现 `org.springframework.beans.factory.DisposableBean` 或者 `java.lang.AutoCloseable`
if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
return true;
}
String destroyMethodName = beanDefinition.getDestroyMethodName();
//@Bean 定义的bean. BeanDefinition的 destoryMethodName=AbstractBeanDefinition.INFER_METHOD
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
}
//自定义destory-method
return StringUtils.hasLength(destroyMethodName);
}
这里就到我们的结论区了
实现 org.springframework.beans.factory.DisposableBean 或者 java.lang.AutoCloseable
@Bean 注解时,自动推断. 存在close() 或者 shutdown() 就调用
自定义destory-method
问题场景
org.apache.commons.dbcp.BasicDataSource 为什么在xml必须定义destory-method而yml不用呢?
xml里面, BeanDefinition的destoryMethodName属性默认为null.
yml里面, 通过@Bean定义的bean, BeanDefinition的destoryMethodName属性默认为(inferred).
也就是说xml必须手动指定, @Bean 就算没指定,也会推断有没有close()或者shutdown方法,有就调用
自动定义
关于springboot中自动定义 DataSource 的相关内容做一个简单的描述
存在 spring.datasource.type 时, 注册相关的Bean
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
【转】spring bean 卸载的更多相关文章
- Spring8:一些常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
- Spring Bean详细讲解
什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象. Spring 容器会自动完成@bean对象的实例化. 创建应用对象之间的协作关系的行为称为:装配( ...
- Spring Bean的生命周期(非常详细)
Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...
- spring bean的生命周期
掌握好spring bean的生命周期,对spring的扩展大有帮助. spring bean的生命周期(推荐看) spring bean的生命周期
- spring bean的重新加载
架构体系 在谈spring bean的重新加载前,首先我们来看看spring ioc容器. spring ioc容器主要功能是完成对bean的创建.依赖注入和管理等功能,而这些功能的实现是有下面几个组 ...
- Spring Bean
一.Spring的几大模块:Data access & Integration.Transcation.Instrumentation.Core Spring Container.Testin ...
- 【转】Spring bean处理——回调函数
Spring bean处理——回调函数 Spring中定义了三个可以用来对Spring bean或生成bean的BeanFactory进行处理的接口,InitializingBean.BeanPost ...
- 在非spring组件中注入spring bean
1.在spring中配置如下<context:spring-configured/> <context:load-time-weaver aspectj-weaving=&q ...
- spring bean生命周期管理--转
Life Cycle Management of a Spring Bean 原文地址:http://javabeat.net/life-cycle-management-of-a-spring-be ...
随机推荐
- 查看已安装dpkg包的poinst安装文件
/var/lib/dpkg/info |grep printburn(软件名称) /var/lib/dpkg/info 文件都在这个目录下面poinst, preinst,prerm等
- A+B for Polynomials
This time, you are supposed to find A+B where A and B are two polynomials. Input Specification: Each ...
- 在ensp上的ARP及Proxy ARP
啥是ARP?啥又是Proxy ARP? ARP是用来将 IP 地址解析为 MAC 地址的协议. ARP 表项可以分为动态和静态两种类型.动态 ARP ,是利用 ARP 广播报文,动态执行并自动进行 I ...
- Java开发笔记(一百二十九)Swing的输入框
Swing的输入框仍然分成两类:单行输入框和多行输入框,但与AWT的同类控件相比,它们在若干细节上有所调整.首先说单行输入框,AWT的单行输入框名叫TextField,平时输入什么字符它便显示什么字符 ...
- C++容器简介1—stack
一.简介 stack是一种容器适配器(STL的容器分为顺序容器和关联容器,容器适配器),被设计来用于操作先进后出(FILO)结构的情景,在这种情况下, 元素的插入和删除都只能在容器的尾部进行. sta ...
- Django最全思维导图
思维导图传送门
- helm chart应用使用示例
有两种方法 一是按照正常流程直接用yaml文件的形式发布应用到k8s集群上 二是把生成好的yaml文件发布到kubeapps应用商店,在应用商店中操作发布应用到k8s集群中 这里采用第二种方式的变种方 ...
- Spring Gateway配置使用(一)
参考文档:Spring Gateway官方文档 , 玹霖的博客 1.Spring Gateway简介 Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring ...
- nginx配置http静态站点服务器
1. 系统环境Windows 10 2. 设置静态站点目录,注意不要出现中文(这里踩了很多坑,可以查看错误日志error.log, “No mapping for the Unicode char ...
- Javascript实现的智能消防栓状态监测画面
系统需要添加智能消防栓模块.集成了一家采用NbIOT通讯的智能消防栓产品.由第厂家平台对接NbIot特联网平台,我们平台提供一个api从第三方平台接收消防栓状态,用SignlaR把状态推送到前端.需要 ...