我有一个支持网站,我想通过JMX显示从另一个Java应用程序收集的一些统计数据。我们注意到,在重新启动其他应用后,支持应用有时无法获取统计信息。我想这是因为支持应用程序已打开与其他应用程序的JMX连接并保持它。然后,每次进入页面显示JMX统计信息时,它都会尝试使用连接收集它们,然后失败。
我的问题是,拥有一个JMX连接并尝试在重新连接时解决它是否更好?
或者每当我们加载带有JMX统计数据的页面时,我们是否应该创建一个新的JMX连接,然后在获得所需的值后关闭它?
答案 0 :(得分:1)
据我所知,
JMX连接是RMI Connector对象,因此可以保存在客户端应用程序中。 +使用心跳方法重新连接。
这样我们就可以避免重新建立不轻量级的RMI连接的开销。
参考:javax.management.remote.rmi.RMIConnector
答案 1 :(得分:0)
我们最终没有使用心跳,但在阅读了Girish的回答之后提出了以下内容
public class JmxMetricsRetriever {
private final JMXServiceURL jmxUrl;
private final Map<String, Object> env;
private MBeanServerConnection connection;
private JmxMetricsRetriever(JMXServiceURL jmxUrl, Map<String, Object> env) {
this.jmxUrl = jmxUrl;
this.env = env;
reconnect();
}
public synchronized Object getAttributeValue(String jmxObjectName, String attributeName) {
try {
if (connection == null) {
reconnect();
}
try {
return getAttributeValuePrivate(jmxObjectName, attributeName);
} catch (ConnectException exc) {
//This is to reconnect after the Server has been restarted.
reconnect();
return getAttributeValuePrivate(jmxObjectName, attributeName);
}
} catch (MalformedObjectNameException |
AttributeNotFoundException |
MBeanException |
ReflectionException |
InstanceNotFoundException |
IOException ex) {
throw new RuntimeException(ex);
}
}
private synchronized Object getAttributeValuePrivate(String jmxObjectName, String attributeName) throws MalformedObjectNameException, MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException {
ObjectName replication = new ObjectName(jmxObjectName);
return connection.getAttribute(replication, attributeName);
}
private synchronized void reconnect() {
logger.info(String.format("Reconnecting to [%s] via JMX", jmxUrl.toString()));
try {
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, env);
this.connection = jmxConnector.getMBeanServerConnection();
jmxConnector.connect();
} catch (IOException e) {
//Log something but don't throw an exception otherwise our app will fail to start.
}
}
public static JmxMetricsRetriever build(String url, String port, String user, String password) {
try {
JMXServiceURL jmxUrl = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + url + ":" + port + "/jmxrmi");
Map<String, Object> env = new HashMap<>();
env.put(JMXConnector.CREDENTIALS, new String[]{user, password});
return new JmxMetricsRetriever(jmxUrl, env);
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
}
}
当我们启动我们的应用程序时,我们尝试创建一个JMX连接并保持它。每次我们获得JMX属性时,我们都会检查连接是否已创建(如果我们连接的服务器在启动我们的服务时未启动,则可能没有)。然后尝试检索我们的属性。如果失败,请尝试重新连接并获取属性值。我们找不到更好的方法来测试JMX连接仍然可用,因此必须捕获异常。