【问题标题】:How to connect to a java program on localhost jvm using JMX?如何使用 JMX 连接到 localhost jvm 上的 java 程序?
【发布时间】: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 作为输入参数的方法。

【问题讨论】:

标签: java localhost rmi jmx jconsole


【解决方案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 及更高版本的程序。

        【讨论】:

          猜你喜欢
          • 2023-04-04
          • 2012-11-23
          • 1970-01-01
          • 2017-01-21
          • 1970-01-01
          • 2011-12-24
          • 2018-06-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多