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.pswp.cn/news/530725.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/530725.shtml
英文地址,請注明出處:http://en.pswp.cn/news/530725.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SSM 整合 4:Spring IoC 容器基于的兩個重要接口 BeanFactory 和 ApplicationContext

文章目錄 前言一、BeanFactory 接口1.1、加載 Spring 配置文件創建 BeanFactory 接口實例1.2、開發中的運用以及使用說明二、ApplicationContext 接口2.1、ClassPathXmlApplicationContext 創建接口實例2.2、FileSystemXmlApplicationContext 創建接口實例2.3、通過 Web 服務器…

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 章——獲取客戶的需求 重點部分總結

文章目錄 前言一、簡答題總結前言 軟件需求分析就是把軟件計劃期間建立的軟件可行性分析求精和細化,分析各種可能的解法,并且分配給各個軟件元素。需求分析是軟件定義階段中的最后一步,是確定系統必須完成哪些工作,也就是對目標系統提出完整、準確、清晰、具體的要求。本文…