Java RMI 远程方法调用 和 Spring 封装

32 篇文章 0 订阅

Java RMI 的基本使用


RMI(remote method invocation,远程方法调用)Java 的 RPC 解决方法调用,用于不同 JVM 虚拟机的通信,这些虚拟机可以位于不同主机,或者同一个主机上面,由一个 JVM 上的对象调用另一个 JVM 上的对象的方法,是分布式系统通信的解决方案之一;

以下通过一个示例,来演示 RMI 远程调用方法的过程;



服务端

创建远程方法接口 server/Hello
 
package basic_sample.server;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote{
    public String say(String message) throws RemoteException;
}

在服务端创建远程方法接口的实现类 server/HelloImpl
 
package basic_sample.server;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject implements Hello{
    public HelloImpl() throws RemoteException {
        super();
    }
    @Override
    public String say(String message) throws RemoteException {
        return "Remote class Hello # say :" + message;
    }
}

创建服务端程序用于注册远程方法接口  server/HelloServer
需要注意的是,在注册远程方法接口的服务端必须定义一个 serialVersionUID,并且和客户端保持一致的值,因为 RMI 远程方法对象的传输涉及到对象序列化;
 
package basic_sample.server;
import java.rmi.Naming;
public class HelloServer {
    private static final long serialVersionUID =  4077329331699621321L;
    public static void main(String[] args){
        try {
            Hello hello = new HelloImpl();
            Naming.bind("rmi://127.0.0.1:1099/Hello",hello);
            System.out.println("server start");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端

同样创建一个远程方法接口 client/Hello,该接口必须和服务端的对应远程方法接口在接口名,接口方法上完全一直(否则可能出现调用方法失败);

创建远程方法调用客户端 client/HelloClient
package basic_sample.client;
import java.rmi.Naming;
public class HelloClient {
    private static final long serialVersionUID =  4077329331699621321L;
    public static void main(String[] args){
        try {
             Hello hello = (Hello) Naming.lookup("rmi://127.0.0.1:1099/Hello");
             System.out.println(hello.say("Hello world"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

启动程序步骤

  • 首先编译服务端的远程方法接口和接口实现类:server/Hello,server/HelloImpl(当然要把其他代码一起编译了也可以);
  • 如果是 JDK 1.4 以前需要手动像注册远程方法接口,JDK 1.4 之后可以直接启动注册程序,会自动注册 classpath 中的所有远程方法对象,该程序位于 JAVA_HOME/bin/rimregister,如果之前以将 JAVA_HOME/bin 添加到全局变量,可以直接运行以下指令:
 
rmiregister 1099
后面参数为 rmi 端口,注意需要定位到远程调用接口的 class 目录下运行该指令,如果是 maven 编译的工程,需要定位到 traget/classes/ 下,如果是 gradle 编译的工程,则在 build/classes/ 下;
  • 之后分别编译启动服务端和客户端 HelloServer,HelloClient 即可;

在以上示例中可以看到,使用 RMI 方式编程程序,即使在客户端并没有 Hello 接口的是实现类,客户端可以调用服务端编写的 Hello 接口实现类,这一过程对客户端是透明的,仿佛该接口是实现类在客户端本地一样,这样在服务端可以很透明地修改 Hello 接口的实现类代码来控制客户端的代码;




Spring 封装 RMI 


Spring 对 RMI 提供了进一步的封装,允许服务端口暴露和自动进行RMI远程方法注册,使用以下的类:
org.springframework.remoting.rmi.RmiServiceExporter(提供远程方法自动服务注册)
org.springframework.remoting.rmi.RmiProxyFactoryBean(提供客户端自动获取RMI远程代理类)

以下通过一个示例演示使用,完整代码地址: https://gitee.com/assad/rmi_spring_sample



需要导入的依赖如下:
 
    compile 'org.springframework:spring-core:4.3.11.RELEASE'
    compile 'org.springframework:spring-beans:4.3.11.RELEASE'
    compile 'org.springframework:spring-web:4.3.11.RELEASE'

服务端

创建远程方法接口 server/Hello
 
package basic_sample.server;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote{
    public String say(String message) throws RemoteException;
}

在服务端创建远程方法接口的实现类 server/HelloService
package spring_sample.server;
import java.rmi.RemoteException;
public class HelloService implements Hello{
    @Override
    public String say(String message) throws RemoteException {
        return "Remote class Hello # say :" + message;
    }
}

在 spring 上下文配置文件中添加以下:
 
    <!--装载远程方法接口实现类-->
    <bean id="helloService" class="spring_sample.server.HelloService" scope="prototype" />
    <!-- 配置 RMI 服务-->
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter"
          p:service-ref="helloService"
          p:serviceName="hello"
          p:serviceInterface="spring_sample.server.Hello"
          p:registryPort="1099" />
    <!-- 以上各参数:
         service:将远程接口实现对象注册到 RMI 服务中
         serviceName:设置 RMI 服务名,即 "rmi://xxxip/serviceName"
         serviceInterface:远程方法接口类
         registerPort:设置 RMI 服务端口
         -->

创建服务端启动程序 server/HelloServer
 
package spring_sample.server;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloServer{
    public static void main(String[] args){
        new ClassPathXmlApplicationContext("classpath:spring_sample/server/applicationContext.xml");
        System.out.println("server start");
    }
}

客户端

同样创建一个远程方法接口 client/Hello,该接口必须和服务端的对应远程方法接口在接口名,接口方法上完全一直(否则可能出现调用方法失败);

在 spring 上下文配置文件中添加以下:
   <!--配置 RMI 客户端-->
    <bean id="rmiProxyFactory" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"
          p:serviceUrl="rmi://127.0.0.1:1099/hello"
          p:serviceInterface="spring_sample.client.Hello"
          p:refreshStubOnConnectFailure="true" />

创建服务端启动程序 client /HelloClient
package spring_sample.client;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.rmi.RemoteException;
public class HelloClient {
    public static void main(String[] args) throws RemoteException {
        Hello hello = new ClassPathXmlApplicationContext("classpath:spring_sample/client/applicationContext.xml")
                .getBean("rmiProxyFactory",Hello.class);
        System.out.println(hello.say("Hello world!"));
    }
}

之后分别启动服务端,客户端程序即可;




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值