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

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

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

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

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


person mjafari    schedule 05.04.2011    source источник
comment
И основная программа, и клиент jmx являются автономными программами (Java SE).   -  person mjafari    schedule 05.04.2011
comment
См. Также pongasoft.com/blog/yan/entry/connecting_to_a_local_vm   -  person    schedule 07.03.2012


Ответы (5)


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

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


Что касается подключения "по 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 и публикацию bean-компонентов на удаленные клиенты.

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

person Gray    schedule 05.04.2011
comment
Спасибо, Грей! Можете ли вы (или другие люди) ответить на мой второй вопрос (локальное соединение jmx с использованием PID)? - person mjafari; 09.04.2011
comment
Если по какой-то причине ConnectorAddress имеет значение null, вы можете попытаться загрузить агент динамически. См. pongasoft.com/blog/yan/entry/connecting_to_a_local_vm - person Gábor Lipták; 12.12.2014
comment
у вас есть проблема компиляции в строке: jmxConnector.close (); - person shlomi33; 16.01.2017

Чтобы уточнить, если вас интересует только локальная статистика JMX, вам не нужно использовать удаленный api. Просто используйте java.lang.management.ManagementFactory:

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

List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
...
person cwu9T9    schedule 29.01.2013

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 (применимо только для Программ, использующих Java 6 и выше.

person Umang Desai    schedule 28.12.2012

Самое простое средство:

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) ...
}
person berhauz    schedule 07.11.2016

Вот как вы можете получить JMX-соединение с Java-программой с ее PID (только для версии ‹= Java 8):

import sun.management.ConnectorAddressLink;
import javax.management.*;

public static MBeanServerConnection getLocalJavaProcessMBeanServer(int javaProcessPID) throws IOException {
    String address = ConnectorAddressLink.importFrom(javaProcessPID);
    JMXServiceURL jmxUrl = new JMXServiceURL(address);
    return JMXConnectorFactory.connect(jmxUrl).getMBeanServerConnection();
}
person Fabien    schedule 14.06.2020