如何使用 JMX 连接到 localhost jvm 上的 java 程序?

Posted

技术标签:

【中文标题】如何使用 JMX 连接到 localhost jvm 上的 java 程序?【英文标题】:How to connect to a java program on localhost jvm using JMX? 【发布时间】:2011-07-30 00:08:24 【问题描述】:

我应该使用 JMX 连接到本地 jvm 上的 java 程序。换句话说,我想开发一个 JMX 客户端来在 localhost 上配置一个 java 程序。

不推荐使用 JConsole! JConsole不适合,因为它是通用的JMX客户端,对主程序性能有负面影响。

oracle 站点上的示例使用 RMIConnector 和 host:port 参数,但我不知道: 应该在哪里设置jmx端口?

JConsole 可以选择通过 PID 连接到 java 进程。但是我在 JMX api 中没有找到任何以 PID 作为输入参数的方法。

【问题讨论】:

主程序和jmx客户端都是独立程序(Java SE)。 另见pongasoft.com/blog/yan/entry/connecting_to_a_local_vm 【参考方案1】:

这就是您如何通过它的 PID 获得与 Java 程序的 JMX 连接(仅适用于版本

import sun.management.ConnectorAddressLink;
import javax.management.*;

public static MBeanServerConnection getLocalJavaProcessMBeanServer(int javaProcessPID) throws IOException 
    String address = ConnectorAddressLink.importFrom(javaProcessPID);
    JMXServiceURL jmxUrl = new JMXServiceURL(address);
    return JMXConnectorFactory.connect(jmxUrl).getMBeanServerConnection();

【讨论】:

【参考方案2】:

最简单的意思:

import javax.management.Attribute;
import javax.management.AttributeList;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;

// set a self JMX connection
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// set the object name(s) you are willing to query, here a CAMEL JMX object
ObjectName objn = new ObjectName("org.apache.camel:context=*,type=routes,name=\"route*\"");
Set<ObjectName> objectInstanceNames = mBeanServer.queryNames(objn, null);
for (ObjectName on : objectInstanceNames) 
    // query a number of attributes at once
    AttributeList attrs = mBeanServer.getAttributes(on, new String[] "ExchangesCompleted","ExchangesFailed");
    // process attribute values (beware of nulls...)
    // ... attrs.get(0) ... attrs.get(1) ...

【讨论】:

【参考方案3】:

我们使用类似以下的方式以编程方式连接到我们的 JMX 服务器。您应该使用以下参数运行您的服务器:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.ssl=false

要绑定到特定地址,您需要添加以下 VM 参数:

-Djava.rmi.server.hostname=A.B.C.D

然后您可以使用 JMX 客户端代码连接到您的服务器,如下所示:

String host = "localhost";  // or some A.B.C.D
int port = 1234;
String url = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi";
JMXServiceURL serviceUrl = new JMXServiceURL(url);
JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceUrl, null);
try 
   MBeanServerConnection mbeanConn = jmxConnector.getMBeanServerConnection();
   // now query to get the beans or whatever
   Set<ObjectName> beanSet = mbeanConn.queryNames(null, null);
   ...
 finally 
   jmxConnector.close();

我们还有一些代码可以通过编程方式将自身发布到 VM 参数之外的特定端口,但这比我想象的要复杂得多。


就“通过 pid”连接而言,据我所知,您需要使用 Java6 从 Java 领域进行连接。我没有使用以下代码,但它似乎可以工作。

List<VirtualMachineDescriptor> vms = VirtualMachine.list();
for (VirtualMachineDescriptor desc : vms) 
    VirtualMachine vm;
    try 
        vm = VirtualMachine.attach(desc);
     catch (AttachNotSupportedException e) 
        continue;
    
    Properties props = vm.getAgentProperties();
    String connectorAddress =
        props.getProperty("com.sun.management.jmxremote.localConnectorAddress");
    if (connectorAddress == null) 
        continue;
    
    JMXServiceURL url = new JMXServiceURL(connectorAddress);
    JMXConnector connector = JMXConnectorFactory.connect(url);
    try 
        MBeanServerConnection mbeanConn = connector.getMBeanServerConnection();
        Set<ObjectName> beanSet = mbeanConn.queryNames(null, null);
        ...
     finally 
        jmxConnector.close();
    


我也是SimpleJMX package 的作者,它可以轻松启动 JMX 服务器并将 bean 发布到远程客户端。

// create a new server listening on port 8000
JmxServer jmxServer = new JmxServer(8000);
// start our server
jmxServer.start();
// register our lookupCache object defined below
jmxServer.register(lookupCache);
jmxServer.register(someOtherObject);
// stop our server
jmxServer.stop();

它也有一个客户端接口,但现在它没有任何机制来通过 PID 查找进程——仅支持主机/端口组合(2012 年 6 月)。

【讨论】:

谢谢格雷!你(或其他人)能回答我的第二个问题(本地 jmx 使用 PID 连接)吗? 如果由于某种原因 ConnectorAddress 为空,您可以尝试动态加载代理。见pongasoft.com/blog/yan/entry/connecting_to_a_local_vm 你在这行有编译问题:jmxConnector.close();【参考方案4】:

澄清一下,如果您只对获取本地 JMX 统计信息感兴趣,则不需要使用远程 api。只需使用java.lang.management.ManagementFactory

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
memoryMXBean.getHeapMemoryUsage().getMax();
...

List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
...

【讨论】:

【参考方案5】:
List<VirtualMachineDescriptor> vm = new ArrayList<VirtualMachineDescriptor>();
        jvmList = new JVMListManager();

        vm = jvmList.listActiveVM();

        for (VirtualMachineDescriptor vmD : vm) 
        
            try
            

            //importFrom is taking a process ID and returning a service url in a String Format
            String ServiceUrl = ConnectorAddressLink.importFrom(Integer.parseInt(vmD.id().trim()));
            JMXServiceURL jmxServiceUrl = new JMXServiceURL(ServiceUrl);

            jmxConnector = JMXConnectorFactory.connect(jmxServiceUrl, null);
            con = jmxConnector.getMBeanServerConnection();
            CompilationMXBean compMXBean = ManagementFactory.newPlatformMXBeanProxy(con
                   , ManagementFactory.COMPILATION_MXBEAN_NAME
                   , CompilationMXBean.class);
            catch(Exception e)
            
            //Do Something  
            
        


protected List listActiveVM() 
    List<VirtualMachineDescriptor> vm = VirtualMachine.list();

    return vm;

这要求您在 JVM 启动时为您尝试读取的进程使用 jmxremote 参数。 为了能够做到这一点而不必在启动时传递 jmxremote 参数。您必须使用 attach api(仅适用于使用 Java 6 及更高版本的程序。

【讨论】:

以上是关于如何使用 JMX 连接到 localhost jvm 上的 java 程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JMX 连接到在 EC2 上运行的 Java 实例

如何通过 JMX 远程连接到 Dataproc 上的 Spark 工作器

Apache ActiveMQ 浏览器无法连接到 JMX 控制台

仍然可以使用 Java Mission Control 连接到远程 JMX 但证书已过期?

jmx 无法连接到本地主机

visualvm - 自动(JMX)连接到应用程序?