在做JMX相关的开发过程中,下面这个异常一个会遇到:
2013-7-11 15:58:05 ClientCommunicatorAdmin restart
警告: Failed to restart: java.io.IOException: Failed to get a RMI stub: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: 10.10.4.18; nested exception is:
java.net.ConnectException: Connection refused: connect]
2013-7-11 15:58:06 RMIConnector RMIClientCommunicatorAdmin-doStop
警告: Failed to call the method close():java.rmi.ConnectException: Connection refused to host: 10.10.4.18; nested exception is:
java.net.ConnectException: Connection refused: connect
2013-7-11 15:58:06 ClientCommunicatorAdmin Checker-run
警告: Failed to check connection: java.net.ConnectException: Connection refused: connect
2013-7-11 15:58:06 ClientCommunicatorAdmin Checker-run
但具体解决方式却不是显而易见的。Google了好长时间,大部分都提到了使用完Socket要及时关闭之类的,并不相关。
我大大致分析了java代码后,解决了该问题。
分析过程如下:
我们一般创建一个MBeanServerConnection的过程
JMXServiceURL serviceurl = new JMXServiceURL(url);
JMXConnector conn = JMXConnectorFactory.connect(serviceurl, null);
MBeanServerConnection mbsc = conn
.getMBeanServerConnection();
此时可以用mbsc来获取相应的属性值,执行相应的方法等。但如果此时远程MBeanServer关闭了,不久就会抛出上面的异常。该异常是不受代码控制的,也就是try,catch并不能捕获。
而如果要屏蔽掉异常信息,只能从java代码入手分析。
我们在创建一个JMXConnector时使用如下方式:
JMXConnector conn = JMXConnectorFactory.connect(serviceurl, null);
此时,第二个参数可以指定一些环境信息。
当JMXConnector为RMI的时候,RMI的connect方法中有如下代码:
final long checkPeriod = EnvHelp.getConnectionCheckPeriod(usemap);
communicatorAdmin = new RMIClientCommunicatorAdmin(checkPeriod);
public RMIClientCommunicatorAdmin(long period) {
super(period);
}
其super方法调用:
public ClientCommunicatorAdmin(long period) {
this.period = period;
if (period > 0) {
checker = new Checker();
Thread t = new Thread(checker);
t.setDaemon(true);
t.start();
} else
checker = null;
}
从上面的代码可以看出,RMIConnector的connect方法中会创建一个RMIClientCommunicatorAdmin,该类会根据传入的env创建一个Checker,用来检测MBeanServer和Client的心跳。
其默认值
public static long getConnectionCheckPeriod(Map env) {
return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
0, Long.MAX_VALUE);
}
大于0,所以Checker会成功创建。
通过以上分析,如果我们不需要Checker,只需要在创建Connector的时候提供env,设置相应的属性值不大于0就可以了。
所以改成如下创建方式:
JMXServiceURL serviceurl = new JMXServiceURL(url);
Map m = new HashMap();
m.put("jmx.remote.x.client.connection.check.period", 0L);
conn = JMXConnectorFactory.connect(serviceurl, m);
MBeanServerConnection mbsc = conn
.getMBeanServerConnection();
即可成功屏蔽开头提到的异常信息。