简体   繁体   English

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

[英]How to connect to a java program on localhost jvm using JMX?

I should connect to a java program on localhost jvm using JMX.我应该使用 JMX 连接到 localhost jvm 上的 java 程序。 In other words I want to develop a JMX client to config a java program on localhost.换句话说,我想开发一个 JMX 客户端来在本地主机上配置一个 java 程序。

  • Don't recommend using JConsole!不推荐使用 JConsole! JConsole is not suitable because it is general JMX client and have negative effect on main program performance. JConsole 不适合,因为它是通用的 JMX 客户端,对主程序性能有负面影响。

  • Samples on oracle site use RMIConnector and host:port params but I don't know: where should set jmx port? oracle 站点上的示例使用 RMIConnector 和 host:port 参数,但我不知道:应该在哪里设置 jmx 端口?

  • JConsole have an option to connect to java processes by PID. JConsole 可以选择通过 PID 连接到 Java 进程。 But I don't find any method in JMX api that have PID as input param.但是我在 JMX api 中找不到任何将 PID 作为输入参数的方法。

We use something like the following to programatically connect to our JMX servers.我们使用类似以下内容以编程方式连接到我们的 JMX 服务器。 You should run your server with something like the following arguments:您应该使用类似于以下参数的内容运行您的服务器:

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

To bind to a particular address you'll need to add the following VM arguments:要绑定到特定地址,您需要添加以下 VM 参数:

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

Then you can connect to your server using JMX client code like the following:然后您可以使用 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();
}

We also have code that can programatically publish itself to a particular port outside of the VM arguments but that's more fu than you need I think.我们还有一些代码可以以编程方式将自身发布到 VM 参数之外的特定端口,但这比我想象的要复杂得多。


In terms of connecting "by pid", you need to be using Java6 to do it from Java land as far as I know.在“通过 pid”连接方面,据我所知,您需要使用 Java6 从 Java 土地上进行连接。 I've not used the following code but it seems to work.我没有使用以下代码,但它似乎有效。

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();
    }
}

I've also the author of SimpleJMX package which makes it easy to start a JMX server and publish beans to remote clients.我也是SimpleJMX 包的作者,它可以轻松启动 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();

It does have a client interface as well but right now it doesn't have any mechanisms to find processes by PID -- only host/port combinations are supported (in 6/2012).它也有一个客户端接口,但现在它没有任何通过 PID 查找进程的机制——仅支持主机/端口组合(6/2012)。

To clarify, if you are only interested in getting local JMX stats, you don't need to use the remote api.澄清一下,如果您只对获取本地 JMX 统计信息感兴趣,则不需要使用远程 api。 Just use java.lang.management.ManagementFactory :只需使用java.lang.management.ManagementFactory

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

List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
...
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;
}

This requires you to use the jmxremote argument at JVM startup for the process you are trying to read.这要求您在 JVM 启动时为您尝试读取的进程使用 jmxremote 参数。 TO be able to do it without having to pass a jmxremote argument at startup.无需在启动时传递 jmxremote 参数即可完成此操作。 You will have to use the attach api(only applicable for Programs using Java 6 and higher.您必须使用附加 api(仅适用于使用 Java 6 及更高版本的程序。

Simplest means:最简单的意思:

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) ...
}

This is how you can get a JMX connection to a Java Program with it's PID (for version <= Java 8 only) :这是您如何通过其 PID 获得到 Java 程序的 JMX 连接(仅适用于版本 <= Java 8):

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM