RMI远程调用

前言

前段时间查代码问题时发现应用代码中接口变量指向的实例对象是Naming.lookup(xx) 返回的,但在整个应用里又找不到这个接口的实现,当时就特别好奇,后面才了解到原来就是远程调用(RMI),今天就简单了解了一下。

RMI :远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法

RMI远程调用步骤:

1,客户对象调用客户端辅助对象上的方法

2,客户端辅助对象打包调用信息(变量,方法名),通过网络发送给服务端辅助对象

3,服务端辅助对象将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象

4,调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象

5,服务端辅助对象将结果打包,发送给客户端辅助对象

6,客户端辅助对象将返回值解包,返回给客户对象

7,客户对象获得返回值

代码实现

package com.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
//创建远程方法接口,该接口必须继承自Remote接口
//Remote 接口是一个标识接口,用于标识所包含的方法可以从非本地虚拟机上调用的接口
public interface Hello extends Remote {
	//由于远程方法调用的本质依然是网络通信,只不过隐藏了底层实现,网络通信是经常会出现异常的,
	//所以接口的所有方法都必须抛出RemoteException以说明该方法是有风险的
	
	public String sayHello(String name) throws RemoteException;

}
package com.rmi;

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

//实际传输的时候就是这个类的实例,所以要指定 serialVersionUID ,不想序列化的字段加关键词 transient即可
public class HelloImpl extends UnicastRemoteObject implements Hello {
   
	private static final long serialVersionUID = 1L;

	public HelloImpl() throws RemoteException {

	}

	@Override
	public String sayHello(String name) throws RemoteException {
		return "Hello," + name;
	}
}

package com.rmi.test;

import com.rmi.Hello;
import com.rmi.HelloImpl;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RMISocketFactory;

public class ServerTest {
	public static void main(String[] args) {
		test2();
	}

	//在jdk的bin下有个rmiregistry.exe 需要在项目的classpath下(比如target/classes下)运行该程序
	//rmiregistry 1099 (这个是默认端口) 可以使用 start rmiregistry 命令在后台运行
	private  static void test1(){
		try {
			Hello hello = new HelloImpl();
			Naming.rebind("user", hello);
			System.out.println("rmi server is ready ...");
		} catch (RemoteException | MalformedURLException e) {
			e.printStackTrace();
		}
	}


	//不再通过rmiregistry单独运行 通过编程来实现
	private  static void test2(){
		try {
			Hello hello = new HelloImpl();
			//注册服务
			Registry registry = LocateRegistry.createRegistry(1099);
			registry.rebind("user", hello);
			System.out.println("rmi server is ready ...");
		} catch (RemoteException e ) {
			e.printStackTrace();
		}
	}
}

客户端调用(建议另外启一个项目,这样模拟更真实)

先写一个相同的接口,接口的全限量名要和服务端的保持一致

package com.rmi;

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

/**
* @Description: 远程调用
* @Author: xiaoaa
* @Date: 2020/12/12 
*/ 
public interface Hello extends Remote {

	public String sayHello(String name) throws RemoteException;

}

测试代码
```java
package com.rmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class RmiTest {
	public static void main(String[] args) {
		test2();
	}
	
	private static void test1(){

		try {
			Hello hello = (Hello) Naming.lookup("user");
			System.out.println(hello.sayHello("xiao"));
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private static void test2(){	
		try {
			Hello hello = (Hello) Naming.lookup("rmi://127.0.0.1:1099/user");
			System.out.println(hello.sayHello("xiao"));
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

写得不好的地方,请见谅。大家有踩到坑的也欢迎分享,谢谢。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值