【发布时间】:2014-02-04 14:52:35
【问题描述】:
我正在尝试在我的 java 应用程序中启动嵌入式 JMX 服务器。我想为 RMI 注册表和实际的 RMI 流量(或 JMX 流量,如果你愿意)使用相同的端口。显然这是可能的,因为RMI Registry is merely a Remote Object itself。
另外的困难是我需要使用 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;
}
}
(equals() 和 hashCode() 是由我的 IDE 自动生成的,不要卡在它们上面)
我这样创建 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() 出现绑定错误,指出该地址已在使用中。
如果我完全跳过使用套接字工厂:
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();
它按预期工作,即只打开一个端口并且没有错误。
问题:如何让 'single-listening-port-scenario' 与 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 System Property,我猜在像我这样的场景中经常会出现这种情况。
【问题讨论】:
-
您可以考虑使用 SimpleJMX,它可以为您完成很多工作。 256.com/sources/simplejmx
-
我会很高兴,但上次我看它没有使用套接字工厂的功能。我错了吗?
-
背景:没有套接字工厂 RMI/JMX 有点用处,除了在最简单的网络设置上。在企业世界中,主机通常是多宿主的。这就是为什么 ! :-)
-
啊有趣。我得补充一下。
-
为什么需要绑定特定的网卡?