繁体   English   中英

RMI和JMX Socket工厂

[英]RMI and JMX Socket Factories

我正在尝试在我的Java应用程序中启动嵌入式JMX服务器。 我想为RMI注册表和实际的RMI流量使用相同的端口(如果你愿意,可以使用JMX流量)。 显然这是可能的,因为RMI注册表本身只是一个远程对象

增加的难点是我需要使用Socket Factories,因为我需要绑定到特定的NIC。 我从以下开始:

int registryPort = 3012;
int jmxPort = 3012;    // use the same port

这是我的服务器套接字工厂。 相当直接的东西:

public class MyRMIServerSocketFactory implements RMIServerSocketFactory {

    private final InetAddress inetAddress;

    public MyRMIServerSocketFactory(InetAddress inetAddress) {
        this.inetAddress = inetAddress;
    }

    @Override
    public ServerSocket createServerSocket(int port) throws IOException {
        return new ServerSocket(port, 0, inetAddress);
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + (this.inetAddress != null ? this.inetAddress.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final FlexibleRMIServerSocketFactory other = (FlexibleRMIServerSocketFactory) obj;
        if (this.inetAddress != other.inetAddress && (this.inetAddress == null || !this.inetAddress.equals(other.inetAddress))) {
            return false;
        }
        return true;
    }    
}

(我的IDE自动生成equals()hashCode() ,不要卡在它们上面)

我像这样创建RMI注册表:

serverSocketFactory = new MyRMIServerSocketFactory(inetAddressBind);
LocateRegistry.createRegistry(
        registryPort,
        RMISocketFactory.getDefaultSocketFactory(),  // client socket factory
        serverSocketFactory // server socket factory
        );       

然后再创建JMXConnectorServer:

JMXServiceURL url = new JMXServiceURL(
     "service:jmx:rmi://localhost:" + jmxPort + 
      "/jndi/rmi://:" + registryPort + "/jmxrmi");

Map env = new HashMap();
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory);

connector = JMXConnectorServerFactory.newJMXConnectorServer(
                url, 
                env,
                ManagementFactory.getPlatformMBeanServer());

connector.start();

这会导致connector.start()上出现绑定错误,说明该地址已被使用。

如果我完全跳过使用Socket Factories:

LocateRegistry.createRegistry(registryPort);

JMXServiceURL url = new JMXServiceURL(
     "service:jmx:rmi://localhost:" + jmxPort + 
      "/jndi/rmi://:" + registryPort + "/jmxrmi");


connector = JMXConnectorServerFactory.newJMXConnectorServer(
                url, 
                null,
                ManagementFactory.getPlatformMBeanServer());

connector.start();

它按预期工作,即只打开一个端口,没有错误。

问题:如何使用Socket Factories实现“单一侦听端口方案”?

更新 - 最终解决方案

如果您使用空客户端套接字工厂创建注册表,它可以工作

LocateRegistry.createRegistry(
        registryPort,
        null,  // client socket factory (let it default to whatever RMI lib wants)
        serverSocketFactory // server socket factory
        );       

我还必须设置java.rmi.server.hostname系统属性 ,我想在像我这样的场景中经常会出现这种情况。

这应该工作:你的ServerSocketFactory中有一个看起来正确的equals()方法,这是重要的一点。 RMI确实称之为。 但是,目前不适用于您的客户端套接字工厂。 您需要传递null作为客户端套接字工厂,而不是RMISocketFactory.getDefaultSocketFactory(),因为它会为您提供sun.rmi.transport.proxy.RMIMasterSocketFactory,由于某种原因它不实现equals() 或者使用合理的equals()方法自己实现RMIClientSocketFactory

所以这里发生的事情是RMI首先比较CSF,并且它们出现不平等,所以它甚至不打扰比较SSF:

csf1.equals(csf2) && ssf1.equals(ssf2)

所以它试图在你指定的端口上创建一个新的ServerSocket ,它与第一个端口相同,所以它失败了。

你可以在equals的开头添加一个快捷方式,如果这= =那就返回true。

您应该搜索JMXMP协议以及包含它的jmxremote_optional.jar。 这是一种更可控,更有效的JMX协议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM