簡體   English   中英

如何通過java代碼設置JMX遠程端口系統環境參數進行遠程監控?

[英]How to set JMX remote port system environment parameters through java code for remote monitoring?

我有一個程序,它需要動態(即在運行時)打開一個可用的套接字並在其上啟動一個JMX代理。 此JMX參數在Java代碼中設置,而不是通過命令行設置。 這很好用。 此后,需要遠程通過Java Visual VM監視(即發出JMX命令等)

該程序中的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之前在程序中完成的第一件事。 不幸的是,它沒有被認可。 只有運行時屬性(即通過命令行指定由Java Visual VM識別JMX連接)。

還遇到了可以從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);
    }
  }
}

任何幫助,將不勝感激!

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中可行,但是在命令行中使用它是另一回事 - 這里有一些討論為什么在Linux上使用Java Attach API會失敗? (即使maven構建完成)但我發現在我的類路徑中添加$ JAVA_HOME / lib / tools.jar解決了這個問題。

你會以一種錯誤的方式解決這個問題。 當您的代碼被調用時,您錯過了這些屬性產生任何影響的機會。

您需要創建一個RmiRegistry,然后創建一個鏈接到平台MBeanServer的JMXConnectorServer,如下所示:

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

如果未將任何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

我嘗試了一些方法來指定java代碼中的jmxremote端口以在特定端口上建立連接,並且已經找到以下內容:

如果指定了jmxremote arg:在我的代碼修改必要的jmxremote System.properties之前, 平台mbean服務器由JVM啟動。 每個mbean服務器都有一個自己的bean注冊表。 平台和JVM mbeans無法以其他方式向其注冊自己的bean。

設置jmx端口屬性后,可以創建備用mbean服務器。 那將監聽你指定的正確的jmx端口。

這樣您就可以選擇平台服務器:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

這樣你自己的

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

還要考慮linux有它的loopback接口,所以你應該明確指定正確的主機名來監聽。

根據手冊, 不建議使用除平台之外的其他MBeanServer,但我可以想象一些命令行選項不是啟動服務器的方式。

這對我有用。 參考Oracle JMX教程 我假設您已經知道如何在下面的示例中使用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) {
            }
        }
    }
}

System.setProperty()-D命令行選項相同。 但是顯然你必須盡早調用它,以便在讀取之前設置屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM