jconsole.exe無法連接到JMX的一種解決方案

今日排查一個遞歸導致的StackOverflow 問題時, 嘗試用jconsole.exe連到 IDEA 中跑的java程序所在的進程ID時, 一直報連接錯誤, 如下:
在這裏插入圖片描述
重試幾次都沒什麼效果, 隨查看防火牆的設置情況, 發現防火牆已關閉. 排除這方面的問題.
如果是Linux, 可以考慮設置防護牆通過策略:

①. 打開防火牆文件: vi /etc/sysconfig/iptables 
②. 添加-A INPUT -m state --state NEW -m tcp -p tcp --dport 8022 -j ACCEPT,   需與(Dcom.sun.management.jmxremote.rmi.port一致)
③. 重啓防火牆, 使其生效 :service iptables restart

後經調試發現, 未合理的配置JXM參數.

JMX(JAVA 管理拓展) 配合Jconsole 來使用是用來分析JVM狀態, 進而發現進程潛在問題的必要途徑, 故合理配置JMX參數至關重要。

遂嘗試使用如下jmx配置參數進行調試, 可以通過測試.

核心配置參數如下:

# 設置jmx遠程配置
-Dcom.sun.management.jmxremote 

# 設置jmx遠程配置的port
-Dcom.sun.management.jmxremote.rmi.port=8022

# 設置jmx遠程配置的ssl
-Dcom.sun.management.jmxremote.ssl=false  

# 設置jmx遠程配置的鑑權
-Dcom.sun.management.jmxremote.authenticate=false

# 設置jmx遠程配置的host地址
-Djava.rmi.server.hostname=localhost

IDEA中的配置樣例如下:
在這裏插入圖片描述

引申:
java.lang.StackOverflowError: null
異常的一般的原因是:
程序產生了 死循環 或 發生無限遞歸.

StackOverflow問題起因:
程序在使用MyBatis-Plus時, 在處理一段插入或更新邏輯(insertOrUpdate)時, 自己準備覆蓋 MyBatis-Plus裏 BaseMapper 裏的 insertOrUpdate方法, 以實現自定義判斷更新的數據條目, 而非根據Entity中所有字段實現全量更新覆蓋. 但在方法命名時, 錯誤的命名爲了update方法, 導致後面在處理數據庫中沒有的業務條目時, 原意是想使用MP裏BaseMapper的insert方法, 但實際上是遞歸調用了該自定義方法.
這將導致所有的操作壓力, 全部指向如下數據庫操作語句selectList :
List existsList = selectList(condition);

/**
     *  業務方法, 會調用如下insert(實際上應爲: insertOrUpdate) 
     *  來處理Entity 在數據庫中的 插入或更新問題.
     */
public void myBizImpl () {
     insert(softwareDownload);
}

/**
     * Biz Desc :
     * 
     * 軟件下載情況統計數據到DB, 
     * 如果數據庫存在該聯合主鍵的數據, 即進行更新;
     * 如果不存在, 即進行插入.
     * 
     * @param softwareDownload  Model層的軟件下載業務Entity
     */
    public boolean insert(SoftwareDownload softwareDownload){
        Wrapper condition = Condition.create().eq("DOWNLOAD_DATE", softwareDownload.getDownloadDate()).and().
                                               eq("DOWNLOAD_CHANNEL", softwareDownload.getDownloadChannel());
        List existsList = selectList(condition); // MP裏baseMapper裏的方法

        if ( null != existsList &&  0 < existsList.size() ) {
            return update(softwareDownload, condition);
        } else {
            return insert(softwareDownload);
        }
    }

解決方案:
將上述方法名 insert 改爲 insertOrUpdate, 目的是覆蓋BaseMapper的insertOrUpdate方法, 用以實現自定義更新.

修改後的方法頭爲 :

public boolean insertOrUpdate(SoftwareDownload softwareDownload){ 
}

其實上述實現數據庫insertOrupdate方法 尚存在一些性能問題, 每次操作都會進行一次query檢查操作, 更爲優雅的詳見引用列表[^1].

通過查詢數據庫的壓力時, 可以順便跟蹤一下數據庫連接池的底層參數配置, 比如 maxActiveSize的默認配置(可以在application-druid.yml裏進行覆蓋).

這時, 查詢mysql連接進程數, 看到如下有8個連接.
show PROCESSLIST;
在這裏插入圖片描述
結合DruidAbstractDataSource源碼查看, 確實是8個:
在這裏插入圖片描述
引用列表:

[^1] MySql實現無則插入有則更新的解決方案

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章