Как настроить параметры среды удаленного порта JMX через код Java для удаленного мониторинга? - PullRequest
9 голосов
/ 02 сентября 2011

У меня есть программа, которая требует динамического (т. Е. Во время выполнения) открытия доступного сокета и запуска на нем агента JMX.Эти параметры JMX устанавливаются внутри кода Java, а не через командную строку.Это отлично работает.После этого необходимо осуществлять удаленный мониторинг (т.е. запускать команды JMX и т. Д.) Через Java Visual VM

Агент сервера RMI в программе находится на линиях готового управления, описанных по адресу: http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html

Вопрос, который у меня есть, можно обобщить следующим образом: как можно установить такие свойства командной строки на уровне системы через код Java, чтобы можно было использовать удаленное профилирование ??

-Dcom.sun.management.jmxremote.port=1234

Если "jmxremote.port "и другие параметры задаются через командную строку, удаленный мониторинг работает нормально.Я пытаюсь найти способ сделать это через Java, а не через командную строку.

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

Процесс требует удаленного мониторинга, и он отлично работает локально.Если в командной строке не указаны следующие параметры, Java Visual VM не подключается к процессу.

-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=10.0.0.128

Я пытался.

System.setProperty("com.sun.management.jmxremote.port",Integer.toString(port));

Это одна из первых операций, выполняемых в программе перед запуском JMXConnectorServer.К сожалению, это не признается.Только свойства времени выполнения (т. Е. Указанные через командную строку распознаются для соединения JMX Java Visual VM).

Также встречался способ извлечения свойств из классов коллекции Java, но не удалось найти способ трассировки свойства."com.sun.management.jmxremote.port ="

public static void setEnv(Map<String, String> newenv) throws Exception {
  Class[] classes = Collections.class.getDeclaredClasses();
  Map<String, String> env = System.getenv();

  for(Class cl : classes) {

    if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {

      Field field = cl.getDeclaredField("m");
      field.setAccessible(true);

      Object obj = field.get(env);
      Map<String, String> map = (Map<String, String>) obj;

      //map.clear();
      map.putAll(newenv);
    }
  }
}

Любая помощь будет принята с благодарностью!

Ответы [ 6 ]

10 голосов
/ 23 июля 2013

Ответ kbec показал путь, но у меня не получилось - однако, посмотрев на этот пост , я смог изменить его и получить рабочее решение.

public static String loadJMXAgent(int port) throws IOException,
        AttachNotSupportedException, AgentLoadException,
        AgentInitializationException {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    VirtualMachine vm = VirtualMachine.attach(name.substring(0,
            name.indexOf('@')));

    String lca = vm.getAgentProperties().getProperty(
            "com.sun.management.jmxremote.localConnectorAddress");
    if (lca == null) {
        Path p = Paths.get(System.getProperty("java.home")).normalize();
        if (!"jre".equals(p.getName(p.getNameCount() - 1).toString()
                .toLowerCase())) {
            p = p.resolve("jre");
        }
        File f = p.resolve("lib").resolve("management-agent.jar").toFile();
        if (!f.exists()) {
            throw new IOException("Management agent not found");
        }
        String options = String.format("com.sun.management.jmxremote.port=%d, " +
                "com.sun.management.jmxremote.authenticate=false, " +
                "com.sun.management.jmxremote.ssl=false", port);
        vm.loadAgent(f.getCanonicalPath(), options);
        lca = vm.getAgentProperties().getProperty(
                "com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    return lca;
}

Это работаетв Eclipse, однако, заставить его работать в командной строке - совсем другое дело - здесь есть некоторые обсуждения Почему использование Java Attach API не работает в Linux?(хотя сборка maven завершается) но я обнаружил, что добавление $ JAVA_HOME / lib / tools.jar в мой путь к классам решило проблему.

4 голосов
/ 18 марта 2016

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

Вам необходимо создать RmiRegistry, а затем создать JMXConnectorServer, связанный с платформой MBeanServer, например:

private void createJmxConnectorServer() throws IOException {
    LocateRegistry.createRegistry(1234);
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:1234/jmxrmi");
    JMXConnectorServer svr = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
    svr.start();
}
2 голосов
/ 20 июня 2012

Если вы не укажете jmxremote env в качестве параметра запуска, агент управления JMX не был загружен.Вы можете попробовать это для динамической загрузки:

public static String loadJMXAgent(int port) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
    System.setProperty("com.sun.management.jmxremote.port", Integer.toString(port));
    String name = ManagementFactory.getRuntimeMXBean().getName();
    VirtualMachine vm = VirtualMachine.attach(name.substring(0, name.indexOf('@')));

    String lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
    if (lca == null) {
        Path p = Paths.get(System.getProperty("java.home")).normalize();
        if (!"jre".equals(p.getName(p.getNameCount()-1).toString().toLowerCase())) p = p.resolve("jre");
        File f = p.resolve("lib").resolve("management-agent.jar").toFile();
        if (!f.exists()) throw new IOException("Management agent not found");

        vm.loadAgent(f.getCanonicalPath(), "com.sun.management.jmxremote");
        lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    return lca;
}

Вы должны включить jdk/lib/tools.jar

1 голос
/ 06 февраля 2014

Я попробовал несколько способов указать порт jmxremote из кода Java для подключения к определенному порту и выяснил следующее:

В случае, если указан jmxremote arg: Сервер платформы mbean запускается JVM до того, как мой код изменяет необходимые свойства jmxremote System.properties. Каждый сервер Mbean имеет собственный реестр компонентов. Компоненты beform и JVM не могут зарегистрировать свои собственные bean-компоненты для него другим способом.

Вы можете создать альтернативный сервер mbean после настройки свойств порта jmx. Он будет прослушивать правильный порт jmx, который вы указали.

Таким образом, вы выбираете сервер платформы:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

Таким образом свой :

System.setProperty("com.sun.management.jmxremote.port","9991");
//...
MBeanServer mbsCustom=MBeanServerFactory.createMBeanServer();

также учтите, что у linux есть интерфейс обратной связи , поэтому вы должны явно указать правильное имя хоста для прослушивания.

Это не рекомендуется использовать другой MBeanServer, кроме платформы, в соответствии с руководствами, но я могу представить некоторые ситуации, когда параметры командной строки не подходят для запуска сервера.

0 голосов
/ 12 апреля 2014

Это то, что работает для меня. Справочник Oracle JMX Tutorial . Я предполагаю, что вы уже знаете, как правильно использовать SimpleMXBean, использованный в следующем примере.

package sample;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import java.util.Map;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class MBServerTest {
    public static void loadJMXAgent(int port, MBeanServer mbs) throws IOException  {
        LocateRegistry.createRegistry(port);
        System.out.println("Initialize the environment map");
        Map<String,Object> env = new HashMap<String,Object>();
        env.put("com.sun.management.jmxremote.authenticate", "false");
        env.put("com.sun.management.jmxremote.ssl", "false");
        System.out.println("Create an RMI connector server");
        JMXServiceURL url =
            new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+port+"/jmxrmi");
        JMXConnectorServer cs =
            JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

        // Start the RMI connector server.
        //
        System.out.println("Start the RMI connector server");
        cs.start();

    }

    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        loadJMXAgent(1199,mbs);

        SimpleStandard cache = new SimpleStandard();

        ObjectName name = new ObjectName(
                "org.javalobby.tnt.jmx:type=ApplicationCacheMBean");
        mbs.registerMBean(cache, name);
        imitateActivity(cache);
    }

    private static void imitateActivity(SimpleStandard cache) {
        while (true) {
            try {
                cache.cacheObject("hello");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}
0 голосов
/ 02 сентября 2011

System.setProperty() идентичен параметру командной строки -D.Однако очевидно, что вы должны вызывать его достаточно рано, чтобы задать свойство перед его чтением.

...