mjafari mjafari - 2 months ago 20
Java Question

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

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

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