在java 1.7中更改了LocateRegistry.createRegistry(int port)吗?

时间:2013-02-07 20:45:05

标签: java rmi jmx

我们的架构中有几个服务器端组件。每个组件都使用JMX来公开各种内部属性。初始化完成如下:

try {       
        Registry registry = null;
        for(int i = _serverInfo.getJMXStartPort(); i <= _serverInfo.getJMXEndPort(); i++) {         
            try {
                registry = LocateRegistry.createRegistry(i);
                if(registry != null) {
                    _statusPort = i;
                    logger.info("Using JMX port: "+_statusPort);
                    break;
                }
            } catch (Exception e) {
                _statusPort++;
            }
        }                               

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        _abstractServiceController = new AbstractServiceController(this);
        ObjectName mbeanName = new ObjectName("MyServer:name=MyServer Service");

        mbs.registerMBean(_abstractServiceController, mbeanName);

        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+_statusPort+"/jmxrmi");
        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, System.getenv(), mbs);
        cs.start();

    } catch (Throwable e) {
        logger.error("Unable to register MBean with JMX");
        e.printStackTrace();
    }

我想我有两个问题。

  1. 这看起来不错吗?

  2. 更大的问题是,虽然这在java 1.6上运行良好(主机上的每个后续服务器都使用下一个可用端口,因为如果端口不可用,LocateRegistry.createRegistry(i)会抛出异常),不是这样在1.7。因此,当第二台服务器尝试JMXConnectorServer.start()时,我们会收到以下异常。有没有人知道createRegistry的行为是否改变了?如果是这样,我们还应该做些什么吗?

    2013-02-07 15:34:28,451 INFO  [main] Using JMX port: 9500
    2013-02-07 15:34:28,929 ERROR [main] Unable to register MBean with JMX
    java.io.IOException: Cannot bind to URL [rmi://:9500/jmxrmi]: javax.naming.NameAlreadyBoundException: jmxrmi [Root exception is java.rmi.AlreadyBoundException: jmxrmi]
            at javax.management.remote.rmi.RMIConnectorServer.newIOException(RMIConnectorServe.java:826)
    at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:431)
    at com.theatre.services.framework.AbstractService.run(AbstractService.java:306)
    at com.theatre.services.reporttree.TreeServerImpl.run(TreeServerImpl.java:690)
    at com.theatre.services.framework.Launcher.main(Launcher.java:99)
    Caused by: javax.naming.NameAlreadyBoundException: jmxrmi [Root exception is java.rmi.AlreadyBoundException: jmxrmi]
    at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:139)
    at com.sun.jndi.toolkit.url.GenericURLContext.bind(GenericURLContext.java:226)
    at javax.naming.InitialContext.bind(InitialContext.java:419)
    at javax.management.remote.rmi.RMIConnectorServer.bind(RMIConnectorServer.java:643)
    at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:426)
    ... 3 more
    Caused by: java.rmi.AlreadyBoundException: jmxrmi
    at sun.rmi.registry.RegistryImpl.bind(RegistryImpl.java:131)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:390)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:248)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:273)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:251)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:377)
    at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
    at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:137)
    ... 7 more
    

1 个答案:

答案 0 :(得分:0)

  

这看起来不错吗?

  • 否。创建注册表可能由于多种原因而失败,而不仅仅是因为端口正在使用中。
  • registrycreateRegistry()之后不能为空,因此对其进行测试毫无意义。
  • 如果您要查找空闲端口,只需打开(并关闭) ServerSocket()即可。 然后在该端口上创建注册表(如果有效)。
  

更大的问题是,虽然这在java 1.6上运行良好(主机上的每个后续服务器都使用下一个可用端口,因为如果端口不可用,LocateRegistry.createRegistry(i)会抛出异常),而不是1.7。

见上文。如果在任何JDK中已经在该端口上运行注册表,则创建注册表也会失败。在早期的JDK中,如果在同一个JVM中的任何端口上运行一个JDK,它将失败。