14

对于服务器端的 RMI,我们需要启动rmiregistry程序,还是只调用LocateRegistry.createRegistry?如果两者都可以,有什么优点和缺点?

4

4 回答 4

8

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

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

于 2008-09-19T03:27:58.297 回答
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 的位置。以下实用程序类和弹簧配置显示了如何实现这一点。

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>

The above example shows how system property be set automatically only when rmi server, rmi client and rmi registry can access the same filesystem. If that is not true or spring codebase is shared via other method (e.g. HTTP), you may modify the CodeBaseResolver to fit your need.

于 2009-06-12T09:43:27.587 回答
0

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

于 2008-09-19T03:53:39.123 回答
0

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

于 2008-09-20T03:57:16.117 回答