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

mjafari picture mjafari · Apr 5, 2011 · Viewed 63.9k times · Source

I should connect to a java program on localhost jvm using JMX. In other words I want to develop a JMX client to config a java program on localhost.

  • Don't recommend using JConsole! JConsole is not suitable because it is general JMX client and have negative effect on main program performance.

  • Samples on oracle site use RMIConnector and host:port params but I don't know: where should set jmx port?

  • JConsole have an option to connect to java processes by PID. But I don't find any method in JMX api that have PID as input param.

Answer

Gray picture Gray · Apr 5, 2011

We use something like the following to programatically connect to our JMX servers. 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:

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

Then you can connect to your server using JMX client code like the following:

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.


In terms of connecting "by pid", you need to be using Java6 to do it from Java land as far as I know. 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.

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