Java 动态远程服务位置-如何注入Spring?

Java 动态远程服务位置-如何注入Spring?,java,spring,rmi,soa,spring-remoting,Java,Spring,Rmi,Soa,Spring Remoting,我目前正在为一个正在工作的项目开发分布式服务体系结构。基本上,我们管理着200多台机器。这些机器中的每一台都有一个运行在其上的服务实例,该实例允许我们以特定的方式与机器交互 在中心,我有一个控制应用程序,需要与这200个相同的服务进行对话。我希望通过SpringRemoting使用RMI来实现这一点,允许我将远程服务@Autowire到@Controller中,并将其视为具有异常传播的本地服务,将来可能还会通过钩子传播事务/安全上下文 这对于一台机器上的单一服务非常有效,我可以在Spring配置

我目前正在为一个正在工作的项目开发分布式服务体系结构。基本上,我们管理着200多台机器。这些机器中的每一台都有一个运行在其上的服务实例,该实例允许我们以特定的方式与机器交互

在中心,我有一个控制应用程序,需要与这200个相同的服务进行对话。我希望通过SpringRemoting使用RMI来实现这一点,允许我将远程服务@Autowire到@Controller中,并将其视为具有异常传播的本地服务,将来可能还会通过钩子传播事务/安全上下文

这对于一台机器上的单一服务非常有效,我可以在Spring配置中对远程服务进行硬编码,但我无法弄清楚的是如何在运行时动态选择要与之对话的服务(也称为哪台机器),并以“Spring”的方式使远程服务可用

我希望能够从数据库表中动态地配置它,并使用相同的表信息进行服务查找,同时仍然利用依赖项注入

我曾想过可能会注入某种服务管理器来执行某种服务查找,但希望其他人能够优雅地解决这个(或类似的)问题

硬编码的单个服务实例的示例如下:

第一个XML片段在机器服务本身上,告诉Spring通过RMI公开它

<!-- Expose DeviceService via RMI -->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
    <property name="serviceName" value="DeviceService" />
    <property name="service" ref="deviceService" />
    <property name="serviceInterface"
        value="com.example.service.DeviceService" />
    <property name="registryPort" value="1199" />
</bean>

第二个XML片段位于客户机(控制应用程序)上,它允许我访问公开的服务

<!-- Proxy our remote DeviceService via RMI -->
<bean id="remoteDeviceService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://machineurl:1199/DeviceService"/>
    <property name="serviceInterface" value="com.example.service.DeviceService"/>
</bean>


这是第二点的配置,我正试图使动态。如您所见,要创建此服务代理,我需要在创建bean时知道服务URL。服务URL可以是200多种变体中的一种,具体取决于我想与哪台机器通话。我正在谈论的服务是同一个接口,但根据当前请求上下文,直到运行时我才知道是哪台机器。

您可以使用附加服务动态创建与服务器的连接,并从客户端/控制器应用程序中删除“remoteDeviceService”,即:

public class RMIConnectionService {

    public DeviceService connect(String serverUrl) {
        RmiProxyFactoryBean factory = new RmiProxyFactoryBean();
        factory.setServiceInterface(DeviceService.class);
        factory.setServiceUrl("rmi://" + serverUrl + ":1099/SERVICE_URL");
        factory.afterPropertiesSet();
        //...
        return (DeviceService) factory.getObject();
    }
}
然后将此服务添加到您的服务层:

<bean id="rmiService" class="...RMIConnectionService" >
    //...
</bean>
对于数据库配置,将DAO添加到此服务,以加载正确的url。端口和url,甚至接口类也可以这样配置


我没有RMI服务来测试这个,但它也与Hessian一起工作。我希望这对您有所帮助。

那么您的控制应用程序就是客户端了?硬编码的版本看起来像什么?我试图让它尽可能成为一个通用的问题,但在这种情况下,“控制”应用程序实际上是另一个服务层,它本身就是这些远程服务的客户端。我将添加一个硬编码的XML配置示例。这就是我对ServiceManager的想法,尽管我不确定实现会是什么样子。此外,我可能希望添加一些缓存,以便每个远程服务URL只有一个代理实例。您的实现看起来是一个可行的选项。使用此实现,使用新端点对此方法的新调用会导致连接异常,因为无法访问缓存的旧端点;它不会更新为使用新端点,即使我们使用的是新端点。
DeviceService server1 = rmiService.connect("127.0.0.1");