我正在尝试在我的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;
}
}
(我的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
System Property我认为在我这样的场景中经常出现这种情况。
答案 0 :(得分:1)
这应该有效:你的ServerSocketFactory中有一个看起来正确的equals()方法,这是重要的一点。 RMI确实称之为。但是,目前不适用于您的客户端套接字工厂。您需要将null
作为客户端套接字工厂传递,而不是RMISocketFactory.getDefaultSocketFactory(),
,因为它会为您提供由于某种原因未实现sun.rmi.transport.proxy.RMIMasterSocketFactory,
的{{1}}。或者使用合理的equals()
方法自己实现RMIClientSocketFactory
。
所以这里发生的事情是RMI首先比较CSF,并且它们出现不平等,所以它甚至不打扰比较SSF:
equals()
所以它尝试在你指定的端口上创建一个新的csf1.equals(csf2) && ssf1.equals(ssf2)
,它与第一个端口相同,所以它失败了。
你可以在equals的开头添加一个快捷方式,如果= =那就返回true。
答案 1 :(得分:0)
您应该搜索JMXMP协议以及包含它的jmxremote_optional.jar。对于JMX来说,这是一个更可控,更有效的协议。