Spring 容器:三种方式解决 Resource leak: ‘applicationContext‘ is never closed 问题

文章目录

  • 前言
  • 一、Spring 容器警告产生的场景
  • 二、Spring 容器未关闭后果分析
    • 2.1、肉眼可见的警告
    • 2.2、导致的内存泄漏
      • 2.2.1、什么是内存泄漏?
      • 2.2.2、如何判断内存泄漏?
      • 2.2.3、Java 中的 GC(垃圾回收)
      • 2.2.4、Java 中会导致内存泄漏的情况
      • 2.2.5、Spring 容器未关闭导致的内存泄漏问题
  • 三、如何手动关闭 Spring 容器(3.2 最常用)
    • 3.1、context.close();
    • 3.2、((ConfigurableApplicationContext) context).close();
      • 3.2.1、导入 org.springframework.context.support.AbstractApplicationContext 包
      • 3.2.2、删掉多余的导包
    • 3.3、使用获取对象公开声明的方法
      • 3.3.1、Method Class.getMethod(String name, Class<?>... parameterTypes)
      • 3.3.2、如何使用该方法关闭 Spring 容器
  • 总结


前言

我们在初始化了 Spring IoC 的容器 ApplicationContext,并加载完配置文件之后,如果不对容器进行处理,首先我们直观上看到的就是 IDE 的警告:Resource leak: 'context' is never closed。其次还有什么其他层次的问题?这类问题我们如何去解决?本文就这类问题提出了三种不同的解决方式,让你通过一个问题解决一类问题。

在这里插入图片描述


一、Spring 容器警告产生的场景

我们初始化了 Spring IoC 的容器 ApplicationContext,并加载完配置文件,创建了一个 Bean 的实例,代码如下:

public class Test {public static void main(String[] args) {// 初始化Spring容器applicationContext,加载配置文件ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 通过容器获取test实例TestDao dao = (TestDao) context.getBean("test");// test为配置文件中的iddao.sayHello();}
}

可以看得到这里我们在使用完容器之后并没有对容器进行处理,然后 IDE 就发出了如下警告:

Resource leak: 'context' is never closed

提示我们:容器没有关闭,警告内容具体如下图所示:

在这里插入图片描述

二、Spring 容器未关闭后果分析

2.1、肉眼可见的警告

对于强迫症来说,这不是要了老命吗?我好好的一个项目你给我来个感叹号?不行我一定要解决!

在这里插入图片描述
使用快捷键快速定位光标行出现的问题,根据提示添加如下代码,什么意思呢?忽略警告。如果你仅仅就是为了去掉警告,你就不必继续往下看了。这个方式完全可以满足你。

@SuppressWarnings("resource")

2.2、导致的内存泄漏

容器未关闭可能会导致内存泄漏,说到这里可能会有人有疑问:

在这里插入图片描述
Java 不是有 GC(垃圾回收)机制吗?怎么会导致内存泄漏呢?别急,我们来一步一步分析。

2.2.1、什么是内存泄漏?

内存泄漏是指不再被使用的对象或变量一直占据在内存中。

2.2.2、如何判断内存泄漏?

检查 Java 中的内存泄漏,一定要将程序各个分支情况都完成执行至结束,然后看其是否被使用过,如果没有才能判定这个对象属于内存泄漏。

2.2.3、Java 中的 GC(垃圾回收)

Java 虚拟机 JVM 会将不再使用的对象或变量从内存中回收来释放内存。
(关于 Java 中 GC 的内容这里不做赘述,可以移步我的相关 Java 专栏查看)

2.2.4、Java 中会导致内存泄漏的情况

  1. 当长生命周期的对象持有短生命周期的对象的引用,就很可能发生内存泄漏。尽管短生命周期的对象已经不再需要,但是长生命周期的对象一直持有它的引用导致其无法被回收。例如,缓存系统;加载一个对象放在缓存系统中,一直不去使用这个对象,但是它一直被缓存引用,所以不会被回收导致缓存泄漏。
  2. 当一个对象被存储进 HashSet 集合中,就不可修改这个对象中用于计算哈希值的属性了。否则,对象修改后的哈希值与刚添加进 HashSet 集合时的哈希值不一样,此时如果将当前对象的引用作为参数,用 contains 方法判断对象是否存在,则会返回找不到对象的结果。这会导致无法从 HashSet 单独删除当前对象,造成内存泄漏。

2.2.5、Spring 容器未关闭导致的内存泄漏问题

Spring IoC 容器在我们开启之后,JVM 无法像回收对象或者变量的那种来进行回收。Spring 容器的生命周期是比较长的,因为它用于管理所有初始化的 Bean,其生命周期在 Bean 之后(具体关于 Spring 的生命周期我们后面会讲到),如果我们不及时关闭它,就会占用内存导致 JVM 效率降低同时造成内存泄漏。当然,这也不符合我们的开发规范。

三、如何手动关闭 Spring 容器(3.2 最常用)

我们该如何解决关闭容器、流的一类问题呢?下面整理了 3 种方法,第一种最为方便,第二种是我们开发中最常使用的方法,第三种是最为简单粗暴的方法,大家可以根据自己需求来使用。

3.1、context.close();

处理 Spring 容器类似于 Scanner 流,我们按照关闭 Scanner 流的思路,打点调用 close() 方法,添加关闭代码如下所示:

context.close();

这时仍然还是报错。根据提示:The method close() is undefined for the type ApplicationContext,我们会得知 close() 方法并未直接定义在 Spring IoC 容器中,使用快捷键快速定位光标行出现的问题,我们对 context 进添加类型转换,如下图所示:

在这里插入图片描述
这个时候就添加了如下一行代码:

((AbstractApplicationContext) context).close();

这样是可以关闭掉 Spring 容器。其解决的就是context.close();的问题。

3.2、((ConfigurableApplicationContext) context).close();

Spring 中定义了关闭掉 Spring 容器的方法 close(),该方法定义在 ApplicationContext 的子类 ConfigurableApplicationContext 中。那我们该如何快速调出它关闭容器呢?

3.2.1、导入 org.springframework.context.support.AbstractApplicationContext 包

我们使用快捷键先进行 3.1 的步骤,然后删掉 3.1 的关闭代码((AbstractApplicationContext) context).close();,重写一次关闭代码context.close();,这个时候我们就可以看到强转的时候多了一个类型 ConfigurableApplicationContext,我们选择这个即可,如下图所示:

在这里插入图片描述
注意:一定要导入 org.springframework.context.support.AbstractApplicationContext 包才会出现 ConfigurableApplicationContext 的强转类型。

这个时候我们的关闭代码就是下面这样的:

((ConfigurableApplicationContext) context).close();

3.2.2、删掉多余的导包

这个时候我们就可以根据提示将多余的导包删掉了,包括上面的 org.springframework.context.support.AbstractApplicationContext。

小结:这个写法是我们在开发中最常用的手动关闭 Spring 容器的方法。

3.3、使用获取对象公开声明的方法

3.3.1、Method Class.getMethod(String name, Class<?>… parameterTypes)

补充的这个方法的作用是获得对象所声明的公开方法,这也是我们在开发中获取对象方法的常用方法:

Method Class.getMethod(String name, Class<?>... parameterTypes)

参数说明

  1. 参数 name 获得当前方法的名字。
  2. 参数 parameterTypes 是按声明顺序标识该方法形参类型。
  3. 如果对象内的方法的形参是 int 类型的,则 parameterTypes 是 int.class。

举例如下:

person.getClass().getMethod("Speak", null);
//获得person对象的Speak方法,因为Speak方法没有形参,所以parameterTypes为nullperson.getClass().getMethod("run", String.class);
//获得person对象的run方法,因为run方法的形参是String类型的,所以parameterTypes为String.class

3.3.2、如何使用该方法关闭 Spring 容器

根据 3.3.1 中的内容,我们可以通过获取 context 对象的方法 close() 并 invoke 掉 context 容器对象(null 值省略),代码如下:

context.getClass().getMethod("close").invoke(context);

但是需要注意,如果使用这个方法,就需要对异常进行处理,我这里对异常进行捕获,完整代码如下:

package cn.bailu.ch1.test;import java.lang.reflect.InvocationTargetException;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.bailu.ch1.dao.TestDao;public class Test {public static void main(String[] args) {// 初始化Spring容器applicationContext,加载配置文件ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 通过容器获取test实例TestDao dao = (TestDao) context.getBean("test");// test为配置文件中的idtry {context.getClass().getMethod("close").invoke(context);} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException| SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}dao.sayHello();}
}

总结

本文就如何关闭 Spring IoC 容器给大家带来了三种常见的解决方式,其中第一种方式是最为简单的,第二种方式是我们在开发中最为常用的,这个方式很大程度上考察了你对于 Spring 源码的了解程度,你了解源码才能知道里面的方法,而第三种方式是最为简单粗暴的,同时也是我们在获取对象其他方法时较为常用的,这个方法考察的就是你对于 Java 基本代码的了解程度,对于使用就根据你自己的需求来了。一个简单的案例足见你的基本功,扎实基础,多看源码!

在这里插入图片描述


我是白鹿,一个不懈奋斗的程序猿。望本文能对你有所裨益,欢迎大家的一键三连!若有其他问题、建议或者补充可以留言在文章下方,感谢大家的支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/530725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SRA 案例:关于华为开发者联盟基础服务文档内容的改进建议(华为开发者联盟文档深度体验官)

文章目录前言一、文档中心的外链跳转问题1.1、问题描述1.2、造成的问题1.3、改进建议二、图片失真和无法放大查看问题2.1、问题描述2.2、造成的问题2.3、改进建议三、个别 SDK 词汇缺少必要的说明3.1、问题描述3.2、造成的问题3.3、改进建议四、邮箱信息的优化4.1、问题描述4.2…

腾讯位置服务:有何优势?如何使用平台创建应用和服务调用的 Key?

文章目录前言一、腾讯位置服务的优势1.1、提供丰富的地图产品1.2、提供行业解决方案1.3、提供其他生态维度的支持1.4、海量的数据基础1.5、丰富的开发文档二、初识腾讯位置服务2.1、用户的注册与登录&#xff08;附专属邀请码&#xff09;2.2、开发者信息的完善三、创建服务平台…

毕业生当头一棒?忆本科四年,高校毕业生与就业单位基本要求差多少?工作还是考研?

文章目录前言一、大学本科前两年的生活1.1、庸庸碌碌、中规中矩1.2、收获了爱情二、大三的改变2.1、学会自律2.2、学会自我总结2.3、眼光要具有前瞻性三、毕业答辩3.1、个人设计答辩3.2、团队设计答辩四、南京之行4.1、铭记历史&#xff0c;感恩先辈4.2、加强自我认知与提升五、…

Gitee 答疑:为什么从 Gitee 平台 Pull 代码到 STS/Eclipse 后文件乱码?逐步排查

文章目录前言一、产生乱码场景1.1、错误描述1.2、解决思路二、解决方式2.1、检查 Git 平台上的源码2.2、Git 的运行原理2.3、修改 IDE 的文本编码格式2.4、重新打开目的文件问题解决2.5、仍存在问题看这里&#xff08;重新拉区合并&#xff09;总结前言 我们从 Gitee 平台 Pull…

flash 异常修复:QQ 的 flash 图标显示异常?QQ 秀、表情加载异常?一招解决

文章目录前言一、产生错误场景1.1、flash 图标显示异常1.2、解决思路二、安装合适版本的 Flash Player2.1、选择合适版本的 Flash Player2.2、安装 Flash Player三、重启 QQ 客户端四、flash 动画加载异常4.1、动画加载异常原因分析4.2、下载安装 flash 修复工具4.3、使用 Flas…

电脑广告多?Windows 自带恶意软件删除工具还不会使用?有必要安装杀毒软件吗?

文章目录前言一、启动恶意软件删除工具二、扫描类型的选择三、启动软件扫描四、恶意软件删除工具的说明五、对于恶意软件处理的建议总结前言 可能有些小伙伴发现&#xff0c;哎&#xff1f;为什么我的电脑弹窗广告这么多&#xff1f;难不成小视频看多了&#xff1f;电脑中毒了&…

《软件项目管理(第二版)》第 8 章——项目团队与干系人 重点部分总结

文章目录 前言一、简答题二、论述题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 8 章——项目…

《软件项目管理(第二版)》第 7 章——项目风险管理 重点部分总结

文章目录 前言一、单选题二、填空题三、简答题四、论述题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二…

《软件项目管理(第二版)》第 6 章——项目质量管理 重点部分总结

文章目录 前言一、单选题二、判断题三、简答题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 6…

《软件项目管理(第二版)》第 5 章——项目进度和成本管理 重点部分总结

文章目录 前言一、填空题二、简答题三、论述题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 5…

《软件项目管理(第二版)》第 1 章——概述 重点部分总结

文章目录 前言一、填空题二、判断题三、简答题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 1…

《软件项目管理(第二版)》第 2 章——项目准备和启动 重点部分总结

文章目录 前言一、单选题二、判断题三、简答题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 2…

《软件项目管理(第二版)》第 3 章——项目计划 重点部分总结

文章目录 前言一、单选题二、填空题三、简答题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 3…

《软件项目管理(第二版)》第 4 章——项目估算 重点部分总结

文章目录 前言一、单选题二、简答题总结前言 学习了项目的开发与发布之后,我们就可以单独对一个项目进行开发了,但是在企业中开发中,除了编码之外,还需要项目管理、团队协作开发等,这就是软件项目管理板块要学习的内容。本文是对《软件项目管理(第二版)》第 4 章——项目…

《软件需求分析(第二版)》第 1 章——软件需求基础知识 重点部分总结

文章目录 前言一、单选题二、填空题三、判断题四、简答题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整…

《软件需求分析(第二版)》第 2 章——客户眼中的需求 重点部分总结

文章目录 前言一、简答题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的要求。本文…

《软件需求分析(第二版)》第 3 章——需求工程的推荐方法 重点部分总结

文章目录 前言一、单选题二、填空题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的…

《软件需求分析(第二版)》第 4 章——需求分析员的职责 重点部分总结

文章目录 前言一、简答题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的要求。本文…

《软件需求分析(第二版)》第 6 章——获取客户的需求 重点部分总结

文章目录 前言一、简答题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的要求。本文…

《软件需求分析(第二版)》第 7 章——聆听客户的需求 重点部分总结

文章目录 前言一、简答题总结前言 软件需求分析就是把软件计划期间建立的软件可行性分析求精和细化,分析各种可能的解法,并且分配给各个软件元素。需求分析是软件定义阶段中的最后一步,是确定系统必须完成哪些工作,也就是对目标系统提出完整、准确、清晰、具体的要求。本文…