簡體   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