我们初始化了 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为配置文件中的id
dao.sayHello();
}
}
可以看得到这里我们在使用完容器之后并没有对容器进行处理,然后IDE就发出了警告:Resource leak: 'context' is never closed
。
提示我们:容器没有关闭。警告内容如下图所示:
对于强迫症来说,这不是要了老命吗?我好好的一个项目你给我来个感叹号?不行我一定要解决!
使用快捷键快速定位光标行出现的问题,根据提示添加如下代码,什么意思呢?忽略警告。如果你仅仅就是为了去掉警告,你就不必继续往下看了。这个方式完全可以满足你。
@SuppressWarnings("resource")
Java 不是有 GC(垃圾回收)机制吗?怎么会导致内存泄漏呢?别急,我们来一步一步分析。
内存泄漏是指不再被使用的对象或变量一直占据在内存中。
检查 Java 中的内存泄漏,一定要将程序各个分支情况都完成执行至结束,然后看其是否被使用过,如果没有才能判定这个对象属于内存泄漏。
Java 虚拟机 JVM 会将不再使用的对象或变量从内存中回收来释放内存。
(关于 Java 中 GC 的内容这里不做赘述,可以移步我的 Java 专栏查看)
Spring IoC 容器在我们开启之后,JVM 无法像回收对象或者变量的那种来进行回收。Spring 容器的生命周期是比较长的,因为它用于管理所有初始化的 Bean,其生命周期在 Bean 之后(具体关于 Spring 的生命周期我们后面会讲到),如果我们不及时关闭它,就会占用内存导致 JVM 效率降低同时造成内存泄漏。当然,这也不符合我们的开发规范。
我们该如何解决关闭容器、流的一类问题呢?下面整理了 3 种方法,第一种最为方便,第二种是我们开发中最常使用的方法,第三种是最为简单粗暴的方法,大家可以根据自己需求来使用。
处理 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();
的问题。
在 Spring 中定义了关闭掉 Spring 容器的方法 close(),该方法定义在 ApplicationContext 的子类 ConfigurableApplicationContext 中。那我们该如何快速调出它关闭容器呢?
我们使用快捷键先进行 3.1 的步骤,然后删掉 3.1 的关闭代码((AbstractApplicationContext) context).close();
,重写一次关闭代码context.close();
,这个时候我们就可以看到强转的时候多了一个类型 ConfigurableApplicationContext,我们选择这个即可,如下图所示:
注意:一定要导入 org.springframework.context.support.AbstractApplicationContext 包才会出现 ConfigurableApplicationContext 的强转类型。
这个时候我们的关闭代码就是下面这样的:
((ConfigurableApplicationContext) context).close();
这个时候我们就可以根据提示将多余的导包删掉了,包括上面的 org.springframework.context.support.AbstractApplicationContext。
小结:这个写法是我们在开发中最常用的手动关闭 Spring 容器的方法。
补充的这个方法的作用是获得对象所声明的公开方法,这也是我们在开发中获取对象方法的常用方法:
Method Class.getMethod(String name, Class<?>... parameterTypes)
参数说明:
举例如下:
person.getClass().getMethod("Speak", null);
//获得person对象的Speak方法,因为Speak方法没有形参,所以parameterTypes为null
person.getClass().getMethod("run", String.class);
//获得person对象的run方法,因为run方法的形参是String类型的,所以parameterTypes为String.class
根据 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为配置文件中的id
try {
context.getClass().getMethod("close").invoke(context);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dao.sayHello();
}
}
感谢大家的支持,我是白鹿,一个不懈奋斗的程序猿。希望本贴能帮助到大家,欢迎大家的一键三连!如果还有什么问题、建议或者补充可以留言在帖子下方,给予更多人帮助!
更多资讯微信搜索公众号【WDeerCode代码圈】