spring 和rmi 的整合

远程调用有很多种,例如: 
1)远程方法调用(RMI) 
2)Spring自己的HTTP invoker 
3)EJB 
4)Web Services 

Rmiremote method invocation,即远程方法调用),使用rmi,使用远程的方法就像使用本地的方法一样方便。HessianBlazeDS等提供了较好的对rmi的支持,但是它们都是基于sevlet的,也就是说要想使用Hessian或者BlazeDS就必须将编写的程序放入web容器中才能运行,在很多情况下是不方便的,比如说如果我们想要客户使用我们的程序,难道我们要求客户一定要安装tomcat这样的web容器不成。所以如何使用Springrmi结合编写javase的程序是下面讨论的重点。对于HessianBlazeDS的使用请参考我的其他文章。

 

要想编写一个RMI程序,首先需要编写的是服务接口(stub),服务接口是在客户端和服务端都必须有的部分,但是服务接口的实现仅在客户端存在。

 

下面给出一个实例程序:

 

1.0 服务端编写

先说服务端的编写,服务端先要提供一个远程访问的接口(就是stub):

package com.guan.springRmiDemo.server;

 

public interface HelloInterface {

 

    public String sayHello(String name);

}

然后需要写至少一个类,实现上述的接口:

package com.guan.springRmiDemo.server;

 

import org.springframework.stereotype.Component;

 

@Component

public class Hello implements HelloInterface{

 

    @Override

    public String sayHello(String name) {

       return "hello "+name;

    }

}

需要写一个Spring的配置类(您可以使用xml形式的配置文档,我比较倾向于写配置类,有关配置类的说明可以看我的一篇关于这方面的博客)

package com.guan.springRmiDemo.server;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.remoting.rmi.RmiServiceExporter;

 

@Configuration

public class ServerConfigure {

 

    //将实现stub的类注入

    private @Autowired Hello hello;

   

    //下面的bean将远程调用的接口暴露给外界客户端

    @Bean

    public RmiServiceExporter serviceExporter()

    {

       RmiServiceExporter rse = new RmiServiceExporter();

       //rmi访问的名字是Hello

       rse.setServiceName("Hello");

       //rmi访问的端口号是1919

       rse.setRegistryPort(1919);

       //rmi暴露给外部的访问接口是HelloInterface接口

       rse.setServiceInterface(HelloInterface.class);

       //rmi实际使用的是Hello类的对象

       rse.setService(hello);

       return rse;

    }

   

}

最后写一个main函数,启动这个rmi的监听器:

package com.guan.springRmiDemo.server;

 

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

 

public class ServerStart {

public static void main(String[] args) {

     AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

//扫描整个server目录

     ctx.scan("com.guan.springRmiDemo.server");

//刷新

     ctx.refresh();

}

}

注意,当初始化Spring环境后,Spring容器会自动的创建并处理监听(就是说,这种情况下执行ctx.refresh之后无法返回,除非你主动终止监听)。

 

2.0 客户端编写

客户端肯定也需要提供与服务端相同的接口:

package com.guan.springRmiDemo.client;

 

public interface HelloInterface {

 

    public String sayHello(String name);

}

假设客户端中的某一个类中使用到了rmi的远程方法,如下:

package com.guan.springRmiDemo.client;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

 

@Component("clientUseHello")

public class ClientUseHello {

 

    private HelloInterface hello;

 

 

//注意,这个服务的代理要以注入的形式赋值给hello变量

    @Autowired

    @Qualifier("helloProxy")

    public void setHello(HelloInterface hello) {

       this.hello = hello;

    }

   

    public void sayHello()

    {

//使用的rmi远程服务

       System.out.println(hello.sayHello("关新全"));

    }

}

下面给出Spring的配置文件:

package com.guan.springRmiDemo.client;

 

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.remoting.rmi.RmiProxyFactoryBean;

 

@Configuration

public class ClientConfigure {

//创建rmi的代理

    @Bean(name="helloProxy")

    public RmiProxyFactoryBean rmiProxy()

    {

       RmiProxyFactoryBean rpfb = new RmiProxyFactoryBean();

//访问rmiip,端口,和rmi名字

       rpfb.setServiceUrl("rmi://202.194.158.128:1919/Hello");

//设置代理类代理的接口

       rpfb.setServiceInterface(HelloInterface.class);

       return rpfb;

    }

}

 

上面有个小细节需要单独说:就是在Spring配置文档中创建的代理bean,实际是RmiProxyFactoryBean类型,而在ClientUseHello中注入的代理却是HelloInterface类型,这个类型转换是由Spring来完成的,由于在创建代理的时候,指定了代理的是HelloInterface接口,Spring可以将这个代理接口转换成我们使用的方式。(RmiProxyFactoryBean如何能转换成HelloInterface类型,是个很有意思的问题,可以深刻探讨下)。

最后给出客户端的测试代码:

package com.guan.springRmiDemo.client;

 

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

 

public class ClientTest {

 

    @Test

    public void rmiTest()

    {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

        ctx.scan("com.guan.springRmiDemo.client");

        ctx.refresh();

        ClientUseHello cuh = (ClientUseHello) ctx.getBean("clientUseHello");

        cuh.sayHello();

    }

}

 

执行结果:

hello 关新全

 

3. 一个灵活的客户端的实现

按照第二步中的方式实现的客户端是在spring容器启动之前就要确定链接的ip地址和端口号,有时我们需要更加灵活的rmi运行方式,比如,在运行时动态的决定需要访问的ip地址和端口号,这时,使用spring容器的方法就不可行,但是可以采用下面的方法来实现。

package com.guan.springRmiDemo.client;

 

import org.springframework.remoting.rmi.RmiProxyFactoryBean;

 

public class OtherClientTest {

    public static void main(String[] args) {

//创建远程代理

       RmiProxyFactoryBean rpfb = new RmiProxyFactoryBean();

//可以根据需要动态设定rmiip地址和端口

       rpfb.setServiceUrl("rmi://202.194.158.128:1919/Hello");

//设置访问接口

       rpfb.setServiceInterface(HelloInterface.class);

//设置结束,让rmi开始链接远程的服务

       rpfb.afterPropertiesSet();

//获取链接后的返回结果

       Object o = rpfb.getObject();

//将结果转换成我们希望的类型

       HelloInterface hello = (HelloInterface)o;

//调用结果执行远程调用

       System.out.println(hello.sayHello("关新全"));

 

    }

 

}

你可能感兴趣的:(rmi)