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实现无则插入有则更新的解决方案

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