Как подключиться к java-программе на localhost jvm с помощью JMX?

Я должен подключиться к java-программе на localhost jvm с помощью JMX. Другими словами, Я хочу разработать клиент JMX для настройки java-программы на localhost.

  • Не рекомендуется использовать JConsole! JConsole не подходит, потому что это общий клиент JMX и отрицательно влияет на производительность основной программы.

  • образцы на сайте oracle используют rmiconnector и host:port params, но я не знаю: где следует установить jmx порт?

  • JConsole имеют возможность подключения к процессам java с помощью PID. Но я не нахожу никакого метода в JMX api, который имеет PID в качестве входного параметра.

4 ответов


мы используем что-то вроде следующего для программного подключения к нашим серверам JMX. Вы должны запустить свой сервер с чем-то вроде следующих аргументов:

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

для привязки к определенному адресу необходимо добавить следующие аргументы виртуальной машины:

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

затем вы можете подключиться к серверу с помощью кода клиента 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();
}

у нас также есть код, который может программно опубликовать на определенный порт снаружи Аргументы VM, но это больше fu, чем вам нужно, я думаю.


С точки зрения подключения "по pid", вам нужно использовать Java6, чтобы сделать это из земли Java, насколько я знаю. Я не использовал следующий код, но, похоже, он работает.

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

у меня также есть автор пакет SimpleJMX что упрощает запуск сервера JMX и публикацию компонентов для удаленных клиентов.

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

Он также имеет клиентский интерфейс, но прямо сейчас он не имеет никаких механизмов для поиска процессов по PID-поддерживаются только комбинации хост/порт (в 6/2012).


чтобы уточнить, если вы заинтересованы только в получении локальной статистики JMX, вам не нужно использовать удаленный api. Просто используйте 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;
}

для этого необходимо использовать аргумент jmxremote при запуске JVM для процесса, который вы пытаетесь прочитать. Чтобы сделать это без необходимости передавать аргумент jmxremote при запуске. Вам придется использовать api attach (применимо только для программ, использующих Java 6 и выше.


простейшие средства:

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