RMI服务器:rmiregistry 或 LocateRegistry.createRegistry
-
01-07-2019 - |
题
对于服务器端的RMI,我们需要启动吗 rmiregistry
程序,或者只是调用 LocateRegistry.createRegistry
?如果两者都可以的话,各有什么优点和缺点?
解决方案
他们是同一件事... rmiregistry
是一个单独的程序,您可以从命令行或脚本运行它,而 LocateRegistry.createRegistry
以编程方式做同样的事情。
根据我的经验,对于“真实”服务器,您将需要使用 rmiregistry
这样您就知道无论客户端应用程序是否启动,它都始终在运行。 createRegistry
对于测试非常有用,因为您可以根据需要从测试中启动和停止注册表。
其他提示
如果我们首先启动 rmiregistry,RmiServiceExporter 会将自身注册到正在运行的 rmiregistry。在这种情况下,我们必须将系统属性“java.rmi.server.codebase”设置为可以找到“org.springframework.remoting.rmi.RmiInitationWrapper_Stub”类的位置。否则,将不会启动rmiserviceexporter,并获得“找不到ClassNotFoundException类:org.springframework.remoting.rmi.RmiInitationWrapper_Stub;嵌套异常是:……”
如果您的 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 以满足您的需要。
如果您正在编写一个独立的 java 应用程序,您可能希望启动自己的 rmiregistry,但如果您正在编写一个明显在 J2EE 容器内运行的 J2EE 应用程序,那么您需要“LocateRegistry”,因为应用程序服务器上已经有一个正在运行!
如果您使用 Spring 导出 RMI 服务,它会自动启动注册表(如果注册表尚未运行)。看 Rmi服务导出器