返回介绍

15.2.2 装配 RMI 服务

发布于 2024-08-17 00:45:49 字数 2863 浏览 0 评论 0 收藏 0

传统上,RMI客户端必须使用RMI API的Naming类从RMI注册表中查找服务。例如,下面的代码片段演示了如何获取Spitter的RMI服务:

虽然这段代码可以获取Spitter的RMI服务的引用,但是它存在两个问题:

传统的RMI查找可能会导致3种检查型异常的任意一种(RemoteException、NotBoundException和MalformedURLException),这些异常必须被捕获或重新抛出;

需要Spitter服务的任何代码都必须自己负责获取该服务。这属于样板代码,与客户端的功能并没有直接关系。

RMI查找过程中所抛出的异常通常意味着应用发生了致命的不可恢复的问题。例如,MalformedURLException异常意味着这个服务的地址是无效的。为了从这个异常中恢复,应用至少要重新配置,也可能需要重新编译。try/catch代码块并不能在发生异常时优雅地恢复,既然如此,为什么还要强制我们的代码捕获并处理这个异常呢?

但是,更糟糕的事情是这段代码直接违反了依赖注入(DI)原则。因为客户端代码需要负责查找Spitter服务,并且这个服务是RMI服务,我们甚至没有任何机会去提供SpitterService对象的不同实现。理想情况下,应该可以为任意一个bean注入SpitterService对象,而不是让bean自己去查找服务。利用DI,SpitterService的任何客户端都不需要关心此服务来源于何处。

Spring的RmiProxyFactoryBean是一个工厂bean,该bean可以为RMI服务创建代理。使用RmiProxyFactoryBean引用SpitterService的RMI服务是非常简单的,只需要在客户端的Spring配置中增加如下的@Bean方法:

服务的URL是通过RmiProxyFactoryBean的serviceUrl属性来设置的,在这里,服务名被设置为SpitterService,并且声明服务是在本地机器上的;同时,服务提供的接口由serviceInterface属性来指定。图15.5展示了客户端和RMI代理的交互。

图15.5 RmiProxyFactoryBean生成一个代理对象,该对象代表客户端来负责与远程的RMI服务进行通信。客户端通过服务的接口与代理进行交互,就如同远程服务就是一个本地的POJO

现在已经把RMI服务声明为Spring管理的bean,我们就可以把它作为依赖装配进另一个bean中,就像任意非远程的bean那样。例如,假设客户端需要使用Spitter服务为指定的用户获取Spittle列表,我们可以使用@Autowired注解把服务代理装配进客户端中:

我们还可以像本地bean一样调用它的方法:

以这种方式访问RMI服务简直太棒了!客户端代码甚至不需要知道所处理的是一个RMI服务。它只是通过注入机制接受了一个SpitterService对象,根本不必关心它来自何处。实际上,谁知道客户端得到的就是一个基于RMI的实现呢?

此外,代理捕获了这个服务所有可能抛出的RemoteException异常,并把它包装为运行期异常重新抛出,这样我们就可以放心地忽略这些异常。我们也可以非常容易地把远程服务bean替换为该服务的其他实现——或许是不同的远程服务,或者可能是客户端代码单元测试时的一个mock实现。

虽然客户端代码根本不需要关心所赋予的SpitterService是一个远程服务,但我们需要非常谨慎地设计远程服务的接口。提醒一下,客户端不得不调用两次服务:一次是根据用户名查找Spitter,另一次是获取Spittle对象的列表。这两次远程调用都会受网络延迟的影响,进而可能会影响到客户端的性能。清楚了客户端是如何使用服务的,我们或许会重写接口,把这两个调用放进一个方法中。但是现在我们要接受这样的服务接口。

RMI是一种实现远程服务交互的好办法,但是它存在某些限制。首先,RMI很难穿越防火墙,这是因为RMI使用任意端口来交互——这是防火墙通常所不允许的。在企业内部网络环境中,我们通常不需要担心这个问题。但是如果在互联网上运行,我们用RMI可能会遇到麻烦。即使RMI提供了对HTTP的通道的支持(通常防火墙都允许),但是建立这个通道也不是件容易的事。

另外一件需要考虑的事情是RMI是基于Java的。这意味着客户端和服务端必须都是用Java开发的。因为RMI使用了Java的序列化机制,所以通过网络传输的对象类型必须要保证在调用两端的Java运行时中是完全相同的版本。对我们的应用而言,这可能是个问题,也可能不是问题。但是选择RMI做远程服务时,必须要牢记这一点。

Caucho Technology(Resin应用服务器背后的公司)开发了一套应对RMI限制的远程调用解决方案。实际上,Caucho提供了两种解决方案:Hessian和Burlap。让我们看一下如何在Spring中使用Hessian和Burlap处理远程服务。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文