3

我正在尝试为通过 WebStart 的应用程序启动器实现基于 JMX 的 RMI 连接器的监视控制。

从命令行或 IDE 启动应用程序时,无论我如何启动它们,连接器都能正常工作。但是,当我通过使用 javaws 调用 JNLP 文件启动它时尝试检查它时,一切都变了。

我尝试了几种方法:

  • 使用内置的 JMX 功能,通过在 JAVAWS_VM_ARGS 中指定以下变量(文档说它应该在 1.6 中工作,但人们报告它没有;如果我检查,它们似乎在结果过程中根本没有设置它使用附加 API):

    -Dcom.sun.management.jmxremote
    -Dcom.sun.management.jmxremote.local.only=true
    -Dcom.sun.management.jmxremote.port=SOME_PORT_HERE
    -Dcom.sun.management.jmxremote.authenticate=false
    -Dcom.sun.management.jmxremote.ssl=false
    
  • 使用内置的 JMX 功能,通过在 JNLP 文件中指定以下变量(有人说这不应该工作,实际上当我使用 Attach API 检查时它们似乎没有设置;JNLP 设置为所有- 权限):

    <property name="com.sun.management.jmxremote.local.only" value="true" />
    <property name="com.sun.management.jmxremote.port" value="SOME_PORT_HERE" />
    <property name="com.sun.management.jmxremote.authenticate" value="false" />
    <property name="com.sun.management.jmxremote.ssl" value="false" />
    
  • 使用内置的 JMX 功能,通过使用 -J 选项向调用javaws程序指定以下变量(如果我使用 Attach API 检查它,它们似乎根本没有在结果过程中设置):

    -J-Dcom.sun.management.jmxremote
    -J-Dcom.sun.management.jmxremote.local.only=true
    -J-Dcom.sun.management.jmxremote.port=SOME_PORT_HERE
    -J-Dcom.sun.management.jmxremote.authenticate=false
    -J-Dcom.sun.management.jmxremote.ssl=false
    
  • 使用带有以下代码的自定义 JMXConnectorServer (连接仍然像以前的尝试一样被拒绝,“连接失败。重试?连接不成功。”):

        try {
            final MBeanServer  mbs     = ManagementFactory.getPlatformMBeanServer();
            final String       jmxPort = System.getProperty("jmx.port");
    
            if (jmxPort != null) {
                final int port = Integer.parseInt(jmxPort);
    
                System.out.println("settings JMX properties");
                System.setProperty("java.rmi.server.randomIDs", "true");
                Map<String, String> env = new HashMap<String, String>();
                env.put("com.sun.management.jmxremote.ssl", "false");
                env.put("com.sun.management.jmxremote.authenticate", "false");
                env.put("com.sun.management.jmxremote.local.only", "true");
                System.out.println("Creating Locate Registry");
                LocateRegistry.createRegistry(port);
                System.out.println("Creating JMX Service URL");
                JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/server");
                System.out.println("Creating new JMX Connector Server");
                JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
                cs.start();
            }
        } catch (final RemoteException e) {
            e.printStackTrace();
        } catch (final MalformedURLException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        }
    

我尝试使用此 JMXServiceURL 与 JConsole 连接(最终,这将通过另一个程序完成,但我尝试从 JConsole 验证 JMX 服务是否正常运行):

    service:jmx:rmi:///jndi/rmi://localhost:SOME_PORT_HERE/jmxrmi

有谁知道如何以编程方式或如何将这些属性传递给 WebStart-ed 进程来执行此操作?

提前致谢。

补充说明

  • 这适用于 Java 1.6+(不是 1.5)。
  • 当我直接调用我的程序并通过命令行传递它们时,这些选项确实有效。
  • 有些人提到直接指定 IP,使用 java.rmi.server.hostname=YOUR_IP。但是,当进程正常启动时,这似乎不需要,所以我认为它与 WebStart 场景无关。
  • 我可以使用与 Attach API 的连接通过 PID 与 JConsole 或 JVisualVM 连接到进程,但最终产品不能依赖于此,因为它需要 JDK 或捆绑 tools.jar,我不认为有是开放的替代品。如果有,那实际上会容易得多,所以如果你知道,请告诉我。

更新:

实际上,当使用我最后一个带有显式的示例时JMXConnectorServer,我在 WebStart 进程的启动时得到一个 NPE,其中:

12:39:28,743 WARN  [App] [trce] java.lang.NullPointerException
 at org.jboss.security.jndi.LoginInitialContextFactory.getInitialContext(LoginInitialContextFactory.java:81)
 at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
 at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
 at javax.naming.InitialContext.init(InitialContext.java:223)
 at javax.naming.InitialContext.<init>(InitialContext.java:197)
 at javax.management.remote.rmi.RMIConnectorServer.bind(RMIConnectorServer.java:619)
 at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:412)
 // line invoking .start() on the JMXConnectorServer's instance
4

2 回答 2

0

尝试从 Windows 上的命令行设置以下参数

设置 JAVAWS_VM_ARGS=-Dcom.sun.management.jmxremote.port=9400 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

然后从同一命令提示符启动 jnlp 文件。它对我有用。

于 2012-07-26T05:46:19.473 回答
0

正如问题评论中与jtahlborn所讨论的那样,我们发现这确实特定于应用程序的设置。

要使 JMX 为 WebStart-ed 应用程序工作,需要解决一些缺陷,并且对使用多个 JNDI 上下文工厂也有一些影响。

在这种特殊情况下,应用程序jndi.properties在启动时读取并填充配置设置,因此 JBoss JNDI 上下文工厂甚至已经在 WebStart-ed 应用程序的入口点/主类的静态块的调用点。

由于这些 JNDI 属性对于程序的其余部分是必需的,因此解决方案只是在以JMXServerConnector编程方式创建时覆盖这些属性。

这是一个例子:

    @SuppressWarnings("serial")
    private static Properties   initProperties() {
        return (new Properties() {{
            // overrides for the JNDI factory
            // mostly changing the INITIAL_CONTEXT_FACTORY from:
            //   "org.jboss.security.jndi.JndiLoginInitialContextFactory"
            // to:
            put(Context.INITIAL_CONTEXT_FACTORY,
                "org.jnp.interfaces.NamingContextFactory");
            put(Context.PROVIDER_URL, "jnp://localhost/");

            // Required JMX properties and other things ...
            //  YMMV of course, these were for my current settings
            put("java.rmi.server.randomIDs", "true");
            put("java.rmi.server.hostname", host); // host needs to be an IP
            put("com.sun.management.jmxremote.ssl", "false");
            put("com.sun.management.jmxremote.authenticate", "false");
            put("com.sun.management.jmxremote.local.only", "true");
            put("com.sun.management.jmxremote.port", String.valueOf(port));
        }});
    }

和:

    // error handling left out for clarity
    private static void startJMXAgent() throws TheWorld {
        Registry           reg  = LocateRegistry.createRegistry(port);
        JMXConnectorServer cs   =
            JMXConnectorServerFactory.newJMXConnectorServer(
                new JMXServiceURL(
                    "service:jmx:rmi://" + host + ":" + port + "/" +
                    "jndi/rmi://" + host + ":" + port + "/" +
                    servicename
                ),
                initProperties(),
                ManagementFactory.getPlatformMBeanServer()
            );
        cs.start();
    }

注意:我假设您可能会以相反的方式执行此操作,并在命令行或 JNLP 文件中覆盖这些属性,然后将它们重置为以后上下文所需的任何内容。但是,这不适合这里的用例,所以我没有真正研究它。

于 2012-04-23T13:26:17.293 回答