RMI服务器:rmiregistry或LocateRegistry.createRegistry

时间:2008-09-19 03:19:11

标签: java rmi rmiregistry

对于服务器端的RMI,我们是否需要启动rmiregistry程序,或者只是致电LocateRegistry.createRegistry? 如果两者都有可能,有哪些优点和缺点?

4 个答案:

答案 0 :(得分:7)

它们是相同的... rmiregistry是一个单独的程序,您可以从命令行或脚本运行,而LocateRegistry.createRegistry以编程方式执行相同的操作。

根据我的经验,对于“真正的”服务器,您将需要使用rmiregistry,以便您知道它始终在运行,无论客户端应用程序是否已启动。 createRegistry对测试非常有用,因为您可以根据需要从测试中启动和停止注册表。

答案 1 :(得分:4)

如果我们首先启动rmiregistry,RmiServiceExporter会将自己注册到正在运行的rmiregistry。在这种情况下,我们必须将系统属性'java.rmi.server.codebase'设置为可以找到'org.springframework.remoting.rmi.RmiInvocationWrapper_Stub'类的位置。否则,RmiServiceExporter将无法启动并获得异常“ 找不到ClassNotFoundException类:org.springframework.remoting.rmi.RmiInvocationWrapper_Stub;嵌套异常是:...“

如果您的rmi服务器,rmi客户端和rmiregistry可以访问相同的文件系统,您可能希望系统属性自动配置到可以在共享文件系统上找到spring.jar的位置。以下实用程序类和弹簧配置显示了如何实现此功能。

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注册表可以访问同一文件系统时如何自动设置系统属性。如果不是这样或者通过其他方法(例如HTTP)共享spring代码库,则可以修改CodeBaseResolver以满足您的需要。

答案 2 :(得分:0)

如果您正在编写一个独立的Java应用程序,您可能希望启动自己的rmiregistry,但如果您正在编写显然在J2EE容器内运行的J2EE应用程序,那么您需要“LocateRegistry”,因为已经有一个在应用程序上运行服务器!

答案 3 :(得分:0)

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