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

#java #localhost #rmi #jmx #jconsole

#java #localhost #rmi #jmx #jconsole

Вопрос:

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

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

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

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

Комментарии:

1. Как основная программа, так и клиент jmx являются автономными программами (Java SE).

2. Также смотрите pongasoft.com/blog/yan/entry/connecting_to_a_local_vm

Ответ №1:

Мы используем что-то вроде следующего для программного подключения к нашим серверам 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 land, насколько я знаю. Я не использовал следующий код, но, похоже, он работает.

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

Комментарии:

1. Спасибо Gray! Можете ли вы (или другие пользователи) ответить на мой второй вопрос (подключение к локальному jmx с использованием PID)?

2. Если по какой-либо причине ConnectorAddress равен null, вы можете попробовать загрузить агент динамически. Смотрите pongasoft.com/blog/yan/entry/connecting_to_a_local_vm

3. у вас проблема с компиляцией в строке: jmxConnector.close();

Ответ №2:

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

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

List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
...
  

Ответ №3:

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

Ответ №4:

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

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

Ответ №5:

Вот как вы можете получить 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();
}