web-dev-qa-db-fra.com

Comment se connecter à un programme Java sur jvm localhost en utilisant JMX?

Je devrais me connecter à un programme Java sur jvm localhost en utilisant JMX. En d'autres termes, je veux développer un client JMX pour configurer un programme Java sur localhost.

  • Ne recommande pas d'utiliser JConsole! JConsole ne convient pas car il s'agit d'un client JMX général et a un effet négatif sur les performances du programme principal.

  • Les exemples sur le site Oracle utilisent RMIConnector et Host: port params mais je ne sais pas: où définir le port jmx?

  • JConsole a une option pour se connecter aux processus Java par PID. Mais je ne trouve aucune méthode dans l'API JMX qui a PID comme paramètre d'entrée.

40
mjafari

Nous utilisons quelque chose comme le suivant pour nous connecter par programmation à nos serveurs JMX. Vous devez exécuter votre serveur avec quelque chose comme les arguments suivants:

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

Pour vous lier à une adresse particulière, vous devrez ajouter les arguments VM:

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

Ensuite, vous pouvez vous connecter à votre serveur à l'aide du code client JMX comme suit:

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

Nous avons également du code qui peut se publier par programmation sur un port particulier en dehors des arguments VM mais c'est plus que ce dont vous avez besoin je pense.


En termes de connexion "par pid", vous devez utiliser Java6 pour le faire à partir de Java land pour autant que je sache. Je n'ai pas utilisé le code suivant mais il semble fonctionner.

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

J'ai également l'auteur de package SimpleJMX qui facilite le démarrage d'un serveur JMX et la publication de beans sur des clients distants.

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

Il possède également une interface client, mais pour le moment, il ne dispose d'aucun mécanisme pour rechercher les processus par PID - seules les combinaisons hôte/port sont prises en charge (en 6/2012).

63
Gray

Pour clarifier, si vous souhaitez uniquement obtenir des statistiques JMX locales, vous n'avez pas besoin d'utiliser l'API distante. Utilisez simplement Java.lang.management.ManagementFactory:

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

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

Cela vous oblige à utiliser l'argument jmxremote au démarrage de la machine virtuelle Java pour le processus que vous essayez de lire. POUR pouvoir le faire sans avoir à passer un argument jmxremote au démarrage. Vous devrez utiliser l'API attach (uniquement applicable aux programmes utilisant Java 6 et plus).

3
Umang Desai

Le plus simple signifie:

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
berhauz