¿Cómo conectarse a un programa java en localhost jvm usando JMX?


Debería conectarme a un programa java en localhost jvm usando JMX. En otras palabras, quiero desarrollar un cliente JMX para configurar un programa java en localhost.

  • No se recomienda el uso de JConsole! JConsole no es adecuado porque es un cliente JMX general y tiene un efecto negativo en el rendimiento del programa principal.

  • Las muestras en el sitio de Oracle utilizan RMIConnector y host: parámetros de puerto, pero no lo sé: ¿dónde se debe establecer el puerto jmx?

  • JConsole tiene una opción para conectarse a procesos java por PID. Pero no encuentro ningún método en la api JMX que tenga PID como parámetro de entrada.

Author: mjafari, 2011-04-05

4 answers

Usamos algo como lo siguiente para conectarnos programáticamente a nuestros servidores JMX. Debería ejecutar su servidor con algo como los siguientes argumentos:

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

Para enlazar a una dirección en particular, deberá agregar los siguientes argumentos de VM:

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

Luego puede conectarse a su servidor usando código cliente JMX como el siguiente:

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

También tenemos código que puede publicarse programáticamente en un puerto particular fuera de los argumentos de la VM, pero eso es más fu de lo que necesitas, creo.


En términos de conexión "por pid", necesitas usar Java6 para hacerlo desde Java Land hasta donde yo sé. No he utilizado el siguiente código, pero parece funcionar.

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

También soy el autor del paquete SimpleJMX que hace que sea fácil iniciar un servidor JMX y publicar beans en clientes remotos.

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

También tiene una interfaz de cliente, pero en este momento no tiene ningún mecanismo para encontrar procesos por PID only solo se admiten combinaciones de host / puerto (en 6/2012).

 60
Author: Gray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 21:02:34

Para aclarar, si solo está interesado en obtener estadísticas JMX locales, no necesita usar la api remota. Solo usa java.lang.management.ManagementFactory:

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

List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
...
 4
Author: cwu9T9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-18 12:55:46
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;
}

Esto requiere que use el argumento jmxremote en el inicio de JVM para el proceso que está tratando de leer. PARA poder hacerlo sin tener que pasar un argumento jmxremote al inicio. Tendrá que usar la api attach (solo aplicable para Programas que utilicen Java 6 y versiones posteriores.

 3
Author: Umang Desai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-30 03:11:12

Medios más simples:

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) ...
}
 1
Author: berhauz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-07 16:04:40