Spring学习笔记18

使用RMI

       RMI表示远程方法调用。开发和访问RMI服务非常麻烦,但是Spring提供了一个代理工厂bean来简化RMI模型,它允许你把RMI服务注入到你的Spring应用中就好像本地的JavaBean一样。Spring同时还提供了一个远程服务输出者(exporter)。它可以把你的Spring bean转化成RMI服务。

一、       串联RMI服务

如前所述,RoadRantz需要查询第三方服务。我们可以编写一个工厂方法来获取所需服务的引用:

private String citationUrl = “rmi:/citation/CitationService”;

public CitationService lookupCitationService() throw RemoteException,

       NotBoundException, MalformedURLException {
       CitationService citationService =

(CitationService)Naming.lookup(citationUrl).;

       return citationService;

}

citationUrl属性需要被设置成RMI服务的地址。因此,RoadRantz每次需要使用citation服务时,它都需要调用lookupCitationService方法。这就存在着两个问题:

       ·传统的RMI查询会导致抛出RemoteException, NotBoundExceptionMalformedURLException异常,而我们必须要捕获或重新抛出这些异常。

       ·任何请求citation服务的代码都需要调用lookupCitationService来获取一个服务的引用。

       RMI查询过程中抛出的异常通常都是致命的或是不可恢复的。比如MalformedURLException异常,它就表明给定的服务地址无效。如果要从该异常中恢复至少需要重新配置还有可能要重新编译。没有任何try/catch语句块能够很好地恢复异常。

       另外,lookupCitationService方法更是直接破坏了依赖注入的原则,因为lookupCitationService的客户要确定它在请求一个服务并且需要确定所求服务的位置。理想情况下,你应该把一个CitationService对象注入到需要它的bean中,而不是让那些bean对象自己去查找。依赖注入可以让CitationService的使用者不需要关心CitationService是从哪里来的。

       SpringRmiProxyFactoryBean是一个工厂bean,它会创建一个RMI服务的代理。方法如下:

<?xml version="1.0" encoding="UTF-8"?>

<bean id="citationService"

    class="org.springframework.remoting.rmi.RmiProxyFactoryBean">

    <property name="serviceUrl"

       value="rmi://${citationhost}/CitationService" />

    <property name="serviceInterface"

       value="com.tickettodriver.CitationService" />

</bean>

RMI服务的URL通过serviceUrl属性进行设置。serviceInterface属性指定了服务实现接口。有个被定义为由Spring管理的bean的服务,你就可以把它注入到另一个bean中,就好像你之前注入一个非远程bean一样。比如,假设RantServiceImpl需要使用citation服务来获取车辆的citation列表,使用方法如下:

<bean id="rantService"

    class="com.roadrantz.service.RantServiceImpl">

    <property name="citationService">

       <ref bean="citationService" />

    </property>

</bean>

这种方式访问的好处在于RantServiceImpl并不知道它在处理一个RMI服务。它只是通过DI接收到一个CitationService对象,而不关心接收到的对象从哪里来。另外,代理还会捕获服务抛出的任何RemoteException异常,并重新把它们作为运行时异常抛出,这样你就可以放心地忽略它们了。当你要替换远程服务——可能是另一个服务的实现或是一个用来做单元测试的模拟实现的时候这就显得非常有用。

       RmiProxyFactoryBean简化了RMI服务的使用,但这只是RMI会话的一方面,下面让我们来看看Spring是如何为RMI的服务端提供支持的。

二、       导出RMI服务

创建RMI服务涉及下面的步骤:

·在服务实现类中编写会抛出java.rmi.RemoteException的方法;

·创建服务接口继承java.rmi.Remote

·运行RMI编译器(rmic)产生客户stub类和服务器skeleton类;

·注册RMI服务

我们可以发现,发布一个简单的RMI服务需要做这么多工作。更糟的是,RemoteExceptionMalformedURLException异常会被抛出很多次。这些异常通常都表明哪些不可恢复的致命错误,但是你依然希望编写一段固定代码来捕获和处理这些异常。很明显,没有Spring的帮助,你需要编写很多代码来发布一个RMI服务。

Spring中创建一个RMI服务

       Spring提供了一条简便的方法来发布RMI服务。在Spring中你只需编写一个纯java类就可以执行服务的功能。剩下的工作Spring会为你处理。

       要创建citation查询的RMI服务,我们可以这样做:

public interface CitationService {

       Citation[] getCitationsForVehicle(String stats, String plateNumber);

}

服务接口没有继承java.rmi.Remote并且getCitationsForVehicle方法也没有抛出RemoteException异常,因而简化了接口的开发。更重要的是,一个客户通过这个接口访问服务将不需要捕获那些它们不需要处理的异常。下面你需要定义服务实现类。例如:

public class CitationServiceImpl implements CitationService {

       public CitationServiceImpl() {}

       public Citation[] getCitationsForVehicle(String state, String plateNumber) {

              Citation[] citations;

              …  // looks up citations

              return citations;

}

}

这次CitationServiceImpl是一个纯java类。我们不必实现java.rmi.Remote,也不必抛出RemoteException异常。实际上,这个类并不知道它会以远程方式使用。除此之外,你还需要配置CitationServiceImpl作为Spring配置文件中的一个bean

<bean id="citationService"

    class="com.tickettodrive.CitationServiceImpl">

    ...

</bean>

值得注意的是,没有地方告诉我们这个版本的CitationServiceImpl内部就是一个RMI。它只是一个Spring配置文件中声明的简单java类,和其他声明的POJO没有任何区别。实际上,我们完全可以以一种非远程调用的方式来使用它。

       但这里,我们关心的是以远程调用的方式来使用它。因此,你还需要将CitationServiceImpl作为一个RMI服务导出。与传统的RMI使用rmic和手工注册不同,我们使用Spring提供的RmiServiceExporter

       RmiServiceExporter可以将任何Spring管理的bean作为RMI服务导出。RmiServiceExporter会将bean封装在一个适配器(adapter)类中。adapter类会被绑定到RMI注册表中并以代理的方式向服务类发送请求,在这里就是CitationServiceImpl。配置方式如下:

<bean class="org.springframework.remoting.rmi.RmiServiceExporter">

    <property name="service" ref="citationService" />

    <property name="serviceName" value="CitationService" />

    <property name="serviceInterface"

       value="com.tickettodriver.CitationService" />

</bean>

service属性引用了citationService bean指定RmiServiceExporter将要此bean作为RMI服务导出。serviceName属性为RMI服务命名,serviceInterface属性指定了服务实现的接口。

       默认情况下,RmiServiceExporter将会尝试在端口1099上绑定一个RMI注册表。如果1099上没有找到任何RMI注册表,RmiServiceExporter将会创建一个新的。如果你要绑定一个RMI注册表到一个新的端口或主机,你可以指定registryPortregistryHost属性值。例如:

<bean class="org.springframework.remoting.rmi.RmiServiceExporter">

    <property name="service" ref="citationService" />

    <property name="serviceName" value="CitationService" />

    <property name="serviceInterface"

       value="com.tickettodriver.CitationService" />

    <property name="registryHost" value="rmi.tickettodrive.com" />

    <property name="regestryPort" value="1199" />

</bean>

RMI可以很好地应用于远程服务交互,但是它有自己的局限。首先,RMI通讯时使用随机端口,而防火墙通常是不允许这么做的。其次,RMI是基于java的。这就意味着无论是客户端还是服务器端都需要用java编写。另外因为RMI使用了Java的序列化技术,所以经由网络发送的对象的类型必须在两端严格相同。

       为此,人们开发了HessianBurlap来解决RMi在实际应用中的缺陷。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的、非侵入式的开发方式,通过依赖注入和面向切面编程等特性,简化了Java应用程序的开发过程。 以下是关于Spring学习的一些笔记: 1. IoC(控制反转):Spring通过IoC容器管理对象的创建和依赖关系的注入。通过配置文件或注解,将对象的创建和依赖关系的维护交给Spring容器来管理,降低了组件之间的耦合度。 2. DI(依赖注入):Spring通过依赖注入将对象之间的依赖关系解耦。通过构造函数、Setter方法或注解,将依赖的对象注入到目标对象中,使得对象之间的关系更加灵活和可维护。 3. AOP(面向切面编程):Spring提供了AOP的支持,可以将与业务逻辑无关的横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。 4. MVC(模型-视图-控制器):Spring提供了一个MVC框架,用于构建Web应用程序。通过DispatcherServlet、Controller、ViewResolver等组件,实现了请求的分发和处理,将业务逻辑和视图展示进行了分离。 5. JDBC和ORM支持:Spring提供了对JDBC和ORM框架(如Hibernate、MyBatis)的集成支持,简化了数据库访问的操作,提高了开发效率。 6. 事务管理:Spring提供了对事务的支持,通过声明式事务管理和编程式事务管理,实现了对数据库事务的控制和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值