您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

没事不要乱写close和shutdown方法,搞不好线上就出个大bug

时间:2022-12-02 15:46:24  来源:今日头条  作者:程序员拾山

在Spring项目中,我们在定义一个bean的时候,可能会随手写一个close或者shutdown方法去关闭一些资源。但是有时候这两个看起来很正常的方法名,即使我们不添加任何特殊配置,也可能会给我们带来潜在的bug。

问题复现

通过一个简单的bean重现一下这个问题。

定义一个系统配置类,在某些条件下,我们会调用这个类的close方法去执行一些关闭资源的动作。

@Data
public class SystemConfig {

    private String config;
    private String type;
    //....省略其他属性

    //一个普通的close方法,没有做任何特殊配置
    public void close(){
        //在某些条件下,关闭一些系统资源,不仅局限于本系统
        System.out.println("开始关闭>>>");
    }
}

通过@Bean将这个类注入到Spring容器中:

@SpringBootApplication(scanBasePackages = "com.shishan.demo2023.*")
public class Demo2023Application {

    public static void mAIn(String[] args) {
        SpringApplication.run(Demo2023Application.class, args);
    }

    @Bean
    public SystemConfig systemConfig(){
        SystemConfig systemConfig = new SystemConfig();
        systemConfig.setConfig("config");
        return systemConfig;
    }

}

在很长一段时间内,这段代码都执行得很好。但是有一次系统意外停机时,bug发生了。

 

通过上图可以看到,close方法在没有任何主动调用的情况下,被Spring自动执行了。。。

原理探究

先说结论:问题主要出现在@Bean注解的destroyMethod属性上。

 

我们点开@Bean注解,在destroyMethod方法上,可以看到一段注释。

翻译过来的意思就是:

为了方便用户,容器将尝试针对从 @Bean方法返回的对象推断destroy方法。例如,给定一个 @Bean方法返回一个Apache Commons DBCP BasicDataSource,容器将注意到该对象上可用的close() 方法,并自动将其注册为destroyMethod。

简单来说,当使用@Bean注解时,如果destroyMethod属性没有设置值,Spring会自动检查通过@Bean方法注入的对象是否包含close方法或者shutdown方法,如果有,则将其注册为destroyMethod,并且在bean被销毁时自动调用该方法。

通过搜索destroyMethod的默认值
AbstractBeanDefinition.INFER_METHOD的引用,我们可以在DisposableBeanAdapter类中的inferDestroyMethodIfNecessary方法找到Spring是如何判断close方法的。

@Nullable
private static String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
  String destroyMethodName = beanDefinition.resolvedDestroyMethodName;
  if (destroyMethodName == null) {
    destroyMethodName = beanDefinition.getDestroyMethodName();
    boolean autoCloseable = (bean instanceof AutoCloseable);
    //如果destroyMethod没有定义,而且是默认值
    if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
        (destroyMethodName == null && autoCloseable)) {
      destroyMethodName = null;
      if (!(bean instanceof DisposableBean)) {
        //并且没有实现DisposableBean接口
        if (autoCloseable) {
          destroyMethodName = CLOSE_METHOD_NAME;
        }
        else {
          try {
            //先找close方法
            destroyMethodName = bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
          }
          catch (NoSuchMethodException ex) {
            try {
              //如果close方法没找到,就尝试找shutdown方法
              destroyMethodName = bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
            }
            catch (NoSuchMethodException ex2) {
              // no candidate destroy method found
            }
          }
        }
      }
    }
    beanDefinition.resolvedDestroyMethodName = (destroyMethodName != null ? destroyMethodName : "");
  }
  return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}

通过以上源码我们可以看出,Spring会尝试先找close方法,再找shutdown方法,如果找到了,就将其设置为destroyMethod,如果都没有找到,那就不做处理。

总得来说,建议避免在JAVA类中定义一些带有特殊意义动词的方法,当然如果在线上运行的类已经定义了close或者shutdown方法另作他用,也可以通过将Bean注解内destroyMethod属性设置为显示指定其他方法的方式来解决这个问题。

最后

在实际项目中,用@Bean方式注入的,一般都是第三方包的类。这些第三方包中的类由于没有强依赖Spring,所以无法直接使用@Component、@Service将类注入容器。而且这些类在容器销毁的时候可能也有一些后置处理的需求,为了保持黑盒,Spring就采用这种默认的配置帮助我们执行一些后置处理。如果我们作为第三方开发,建议能够了解这种机制,以免出现一些意想不到的bug。



Tags:close   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
没事不要乱写close和shutdown方法,搞不好线上就出个大bug
在Spring项目中,我们在定义一个bean的时候,可能会随手写一个close或者shutdown方法去关闭一些资源。但是有时候这两个看起来很正常的方法名,即使我们不添加任何特殊配置,也可能...【详细内容】
2022-12-02  Search: close  点击:(361)  评论:(0)  加入收藏
网络连接存在大量time_wait和close_wait的原因以及解决方法
如果对tcp中的握手挥手不了解的同学,请先看这篇博客:《关于三次握手与四次挥手你要知道这些》。 四次挥手过程:第一次挥手:主机A(可以是客户端,也可以是服务器端),设置Sequence Numb...【详细内容】
2021-06-04  Search: close  点击:(840)  评论:(0)  加入收藏
▌简易百科推荐
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(2)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(7)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
站内最新
站内热门
站内头条