Java RMI技术初探

最近在使用dubbo进行项目开发,在使用过程中想到了Java中的RMI技术,这里记录一下关于RMI我的理解,以及简单使用的示例代码。

RMI简述

RMI全称是 Remote Method Invocation,也就是远程方法调用,它可以看做是RPC的Java形式,RMI只能用于Java语言中的远程方法调用。下面是一张网上描述RMI过程的图片。

Java RMI技术初探_第1张图片

RMI个人理解

下面是我对于RMI的个人理解,仅仅是为了让我更好的理解RMI,请谨慎参考。

RMI我认为是通过序列化等技术,将参数传递给远程服务对象的方法进行处理的。

首先服务端申明接口继承于Remote接口,并在这个接口中声明所有要远程调用的方法(方法需要抛出RemoteException异常),然后创建真正的实现类继承UnicastRemoteObject以及实现上面创建的远程调用的接口,然后要执行rmic -keep com.zhl.HelloImpl方式生成存根(Stub),最后就是在主方法(或者服务器启动过程)中将其作为服务抛出去,这样实质上就算是完成了服务端的操作。

而客户端,首先我们将存根(Stub)以及接口代码放到客户端代码中,然后使用Naming.lookup来获取远程的对象的代理,最后使用这个代理来调用远程对象方法。

具体代码

服务端操作

服务端创建被远程调用的接口,并继承Remote.

package com.zhl.rmi.server;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface TestRemote extends Remote{
	public String sayHello() throws RemoteException;
}

服务端创建具体实现类,实现上述接口TestRemote并继承UnicastRemoteObject

package com.zhl.rmi.server.impl;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import com.zhl.rmi.server.TestRemote;

public class TestRemoteImpl extends UnicastRemoteObject implements TestRemote{

	public TestRemoteImpl() throws RemoteException {
		super();
	}

	public int i = 0;
	@Override
	public String sayHello() throws RemoteException{
		System.out.println("Server Hello!");
		System.out.println(i++);
		return "helloFromServer";
	}
	
	
}

使用rmic -keep 指令生成具体实现类对应的存根(Stub),注意这里是在编译的class的根目录下执行的,比如编译的文件到在bin下面,那么就在bin执行rmic -keep 带包名的class 来生成Stub,这里生成的是TestRemoteImpl_Stub且与TestRemoteImpl同一路径。

最后我们将该实现类注册到服务中心

package com.zhl.rmi.server;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

import com.zhl.rmi.server.impl.TestRemoteImpl;

public class Server {
	public static void main(String[] args) throws RemoteException, 
	MalformedURLException, AlreadyBoundException {
		TestRemote testRemote = new TestRemoteImpl();
		LocateRegistry.createRegistry(1888);
		Naming.rebind("rmi://localhost:1888/myTestRemote", testRemote);
		System.out.println("ok!");
	}
}

这里我们创建了对象TestRemote的实现类,LocateRegistry.createRegistry(1888) 创建了端口为1888的注册中心,Naming.rebind("rmi://localhost:1888/myTestRemote",testRemote)将对象以此名称注册到注册中心。

客户端操作

将上面的TestRemote以及生成的TestRemoteImpl_Stub复制到客户端项目中,注意路径需要保持原来的包路径。

调用代码如下

package com.zhl.rmi.client;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import com.zhl.rmi.server.TestRemote;

public class Client {
	public static void main(String[] args) throws RemoteException,
	MalformedURLException, NotBoundException {
		TestRemote testRemote = (TestRemote) Naming.lookup("rmi://localhost:1888/myTestRemote");
		System.out.println(testRemote.sayHello());
		System.out.println(testRemote.toString());
		System.out.println(testRemote.hashCode());
		TestRemote testRemote1 = (TestRemote) Naming.lookup("rmi://localhost:1888/myTestRemote");
		System.out.println(testRemote.sayHello());
		System.out.println(testRemote1.toString());
		System.out.println(testRemote.hashCode());
	}
}

测试调用及分析

首先执行Server的主方法,Server的控制台打印出 ok! 这样说明,我们的服务已经注册成功了。

再执行Client的主方法,这时候可以看到Server的控制台会打印如下:

Java RMI技术初探_第2张图片

而Client的控制台打印类似如下的信息

这样我们就能看出来,我们确实执行了远程方法并成功返回了数据,而且通过Naming.lookup获取的对象是同一对象,方法的真正调用也确实是发生在服务端的。

至此,以上就是我自身对于RMI的理解以及简单的示例调用.

你可能感兴趣的:(Java,Java,RMI)