[英]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.