RMI服务器:rmiregistry或LocateRegistry.createRegistry

14
对于服务器端的RMI,我们需要启动rmiregistry程序吗?还是只需调用LocateRegistry.createRegistry函数即可?
如果两种方法都可行,则有什么优缺点?
4个回答

8
他们是同样的东西...rmiregistry是一个单独的程序,你可以从命令行或脚本中运行它,而LocateRegistry.createRegistry在编程时执行相同的操作。
根据我的经验,在"真正的"服务器中,您将希望使用rmiregistry,以便您知道它始终在运行,无论客户端应用程序是否启动。createRegistry非常适用于测试,因为您可以根据需要启动和停止注册表。

1
除了“localhost”以外,createRegistry有没有办法在接口上工作? - Eagle
更新:文档表明“createRegistry”在本地主机上导出注册表。然而,注册表也可以接受来自外部接口的连接。 - Eagle
@Eagle在本地主机上运行一个注册表。这并不意味着它只监听127.0.0.1。 - user207421

4
如果我们先启动rmiregistry,RmiServiceExporter将会向正在运行的rmiregistry注册自己。在这种情况下,我们需要将系统属性“java.rmi.server.codebase”设置为“org.springframework.remoting.rmi.RmiInvocationWrapper_Stub”类所在的位置。否则,RmiServiceExporter将无法启动并收到异常“ClassNotFoundException class not found: org.springframework.remoting.rmi.RmiInvocationWrapper_Stub; nested exception is: ...”。
如果您的rmi服务器、rmi客户端和rmiregistry可以访问相同的文件系统,您可能希望将系统属性自动配置为可在共享文件系统上找到spring.jar的位置。下面的实用程序类和spring配置展示了如何实现这一点。
abstract public class CodeBaseResolver { 
  static public String resolveCodeBaseForClass(Class<?> clazz) {
    Assert.notNull(clazz);
    final CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
    if (codeSource != null) {
      return codeSource.getLocation().toString();
    } else {
      return "";
    }
  }
}

public class SystemPropertyConfigurer {
  private Map<String, String> systemProperties;
  public void setSystemProperties(Map<String, String> systemProperties) {
    this.systemProperties = systemProperties;
  }

  @PostConstruct
  void init() throws BeansException {
    if (systemProperties == null || systemProperties.isEmpty()) {
      return;
    }
    for (Map.Entry<String, String> entry : systemProperties.entrySet()) {
      final String key = entry.getKey();
      final String value = SystemPropertyUtils.resolvePlaceholders(entry.getValue());
      System.setProperty(key, value);
    }
  }
}


<bean id="springCodeBase" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="staticMethod" value="xx.CodeBaseResolver.resolveCodeBaseForClass" />
  <property name="arguments">
    <list>
      <value>org.springframework.remoting.rmi.RmiInvocationWrapper_Stub</value>
    </list>
  </property>
</bean>

<bean id="springCodeBaseConfigurer" class="xx.SystemPropertyConfigurer"
  depends-on="springCodeBase">
  <property name="systemProperties">
    <map>
      <entry key="java.rmi.server.codebase" value-ref="springCodeBase" />
    </map>
  </property>
</bean>

<bean id="rmiServiceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter" depends-on="springCodeBaseConfigurer">
  <property name="serviceName" value="XXX" />
  <property name="service" ref="XXX" />
  <property name="serviceInterface" value="XXX" />
  <property name="registryPort" value="${remote.rmi.port}" />
</bean>

上面的例子展示了当RMI服务器、RMI客户端和RMI注册表可以访问同一文件系统时,系统属性如何自动设置。如果这不是真实情况,或者Spring代码库通过其他方式共享(例如HTTP),您可以修改CodeBaseResolver以适应您的需求。

0
如果你正在编写一个独立的Java应用程序,你会想要启动自己的rmiregistry,但如果你正在编写一个运行在J2EE容器内的J2EE应用程序,那么你需要使用"LocateRegistry",因为应用服务器上已经有一个在运行了!

虚假和没有动力。您可能也想在独立程序中使用LocateRegistry。 - user207421

0

如果您使用Spring来导出RMI服务,它会自动启动注册表(如果尚未运行)。请参见RmiServiceExporter


你能编辑一下并包含一个链接到这个功能文档吗? - Nathan Feger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接