使用Spring的Bean生命周期特性释放Redis连接池案例

简介

写这篇文章的初衷源于前几天公司的Redis连接池溢出事件,后来是借助SpringBean的生命周期特征解决了连接池溢出问题。基础稍微好点的人应该知道,spring管理的bean,可以自定义初始化方法init,和bean销毁方法destroy,但是以前只是知道有这些特性,工作中从来没有用过,因此比较陌生。

事件还原

连续两天,公司redis连接池溢出,好多项目各种报错,群上开始讨论redis的问题,有的说扩大连接池连接数量,有的说定时重启redis,在我看来这些都解决不了根本问题,然后我说了下自己的看法,结果公司大佬让我去研究问题出在哪里,原以为问题很严重,结果打开代码一看,原来是工具类的一个低级错误。

Redis原有的工具类如下

Redis配置文件的一部分

分析

        很明显,RedisClusterDao工具类并没有加入到spring容器中做统一管理(在配置文件中也没有将Redis工具类加入到Spring容器),其他类在使用的时候都是以new的方式创建新的对象,因此工具类中定义的init方法并不会在new的时候执行,destroy方法也不会在工具类实例销毁时执行,也就是说shardedJedisPool连接池并没有得到释放。

        再看配置文件,MaxTotal的值为-1,一般情况下,-1表示不限制,放在这里应该就是表示不限制redis连接的数量,具体含义我并没有细查,也没查到。

        同时,公司的这台Redis服务是开发人员本地和测试环境服务器共用的,也就是说,开发人员启动本地服务,然后服务中创建了多个redis连接,接着再把这个服务关掉,此时这几个连接并没有释放,注意配置文件中的timeout是6000秒,即100分钟,假设这个程序员在100分钟之内重启了10次本地服务,一次启动建立10个连接,那么就有100个连接不被释放,注意这100个连接并不是到了100分钟立即全部释放,他是有时间差,假设公司有100个开发人员,那么会产生10000个连接,由于配置文件中并没有限制连接数,极端情况下可能更多,所以连接池溢出是迟早的事。

我的解决方案

    A) .控制redis连接池最大连接数量。

    B) .将redis工具类加入到Spring容器做统一管理。

    C) .为了确保destroy方法执行,可通过Spring事件+监听器再次释放redis连接池。

可行性分析

    A方案被大佬质疑,说是担心控制连接数后,应用的连接数会不够

    B方案也被大佬否定,因为说之前就是这样做的,说是出什么问题,所以才用现在的方式。我猜想是因为服务运行过程中因为内存问题,工具类的Bean被回收(Spring中即使是Single的单例Bean也会在内存极度匮乏情况下被回收),因此报错。

    C方案,由于公司架构使用的不是标准的Spring体系(SpringIOC,SpringAOP+CXFService),因此除过Refresh事件,其他事件并不会产生,比如这里需要用到的stop事件,因此这个方案也是不可行。

最终解决思路

    后来,基于原有工具类的灵感,我借助Spring的Bean生命周期特性,添加destroy方法,并且用注解@PreDestroy标识。但是原有的工具类在很多地方有有用到,而且我不知道B方案中大佬所说的问题是什么问题,因此原有的工具类我没有做任何修改。

    虽然原有工具类不能动,但是可以注意到,原有工具类中的shardedJedisPool连接池变量是static类型,因此,我重新定义了一个类,如下

将新定义的类加入到Spring容器当中,这样在容器关闭的时候会调用destroy方法,redis连接池也就得到了释放,但是需要注意,为了方式B方案中我的猜想发生(Bean被回收),我在当前类实现了接口ApplicationLister,这是Spring一个非常中要的接口,而且跟事件相关,因此我猜想实现这个接口的Bean全程不会被回收,也就不会发生B方案中猜想的事情发生。

        也可以用另外一种方式防止Bean被回收的事件发生,那就是将当前新定义的Bean实例加入到ServletContext当中,这样当前Bean实例就会全程被引用,所以不会被回收,这样做相对比较可靠。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值