【问题标题】:RMI server: rmiregistry or LocateRegistry.createRegistryRMI 服务器:rmiregistry 或 LocateRegistry.createRegistry
【发布时间】:2008-09-19 03:19:11
【问题描述】:

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

【问题讨论】:

    标签: java rmi rmiregistry


    【解决方案1】:

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

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

    【讨论】:

    • 除了“localhost”之外,createRegistry 有没有办法在接口上工作?
    • 更新:文档说“createRegistry”在 Localhost 上导出注册表。但是,注册表也能够接受来自外向接口的连接。
    • @Eagle 导出注册表本地主机中运行。没有暗示它只是在听 127.0.0.1。
    【解决方案2】:

    如果我们首先启动 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 server、rmi client 和 rmi registry 可以访问同一个文件系统时,系统属性是如何自动设置的。如果不是这样,或者 spring 代码库是通过其他方法(例如 HTTP)共享的,您可以修改 CodeBaseResolver 以满足您的需要。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 不真实且没有动力。您可能还想在独立程序中使用 LocateRegistry。
      【解决方案4】:

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

      【讨论】:

      • 您可以编辑它以包含指向此功能文档的链接吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-19
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-23
      • 2012-06-15
      相关资源
      最近更新 更多