Java实现简单的RPC过程
RPC是远程过程调用(Remote Procedure Call)的缩写,常用于分布式结构系统中。在分布式系统中,一般将系统组件根据需求进行分解,部署在不同服务器上,系统组件间即可通过RPC进行相互连接调用。
RPC可以实现系统功能间的耦合度降低,系统各服务组件分布在不同服务器上,可独立进行升级和维护;
RPC可以提高系统扩展性和健壮性,通过统一接口控制,实现功能的复用和扩展;
设计案例:设计一个计算器,实现计算器内部方法通过远程调用来获得计算结果
- 设计计算器接口方法及实现类;
- 设序列化对象封装计算器操作数和运算方法;
- 计算器实现类内部将封装对象序列化发送至Server端并等待获取Server端返回的执行结果;
- Server端通过反序列化封装对象获取操作数和运算方法进行本地对应方法调用;
- Server端将本地方法执行结果封装后返回Client端;
- Client端接收Server端执行结果返回至计算器方法调用处完成计算。
Client端构造类:
1、面向用户类
public class Client {
public static void main(String[] args) throws ClassNotFoundException
{
//创建计算器
Calculator calculator=new CalculatorRemoteImpl();
//调用计算器加方法
int result=calculator.add(52,56);
System.out.println(result);
}
}
2、计算器接口:
public interface Calculator {
int add(int i, int j);
}
3、计算器实现类:
实现类内部通过序列化封装对象,发送至Server端,接收Server端执行结果作为方法返回值输出。
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class CalculatorRemoteImpl implements Calculator{
public int add(int a,int b)
{
Socket socket = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
socket = new Socket("127.0.0.1",9000);
//封装计算器操作数,实现可序列化
CalculateRpcRequest calculateRpcRequest = new CalculateRpcRequest(a,b,"add");
//对象输出流,将封装数据的对象序列化写入Socket
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(calculateRpcRequest);
//对象输入流,读入Socket中数据反序列化转换为对象
objectInputStream = new ObjectInputStream(socket.getInputStream());
Object response = null;
try {
response = objectInputStream.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(response instanceof Integer)
{
return (Integer)response;
}
else
{
throw new InternalError();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if(socket!=null)
{
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(objectOutputStream!=null)
{
try {
objectOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(objectInputStream!=null)
{
try {
objectInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return 0;
}
}
4、封装操作数和运算方法的序列化对象
import java.io.Serializable;
public class CalculateRpcRequest implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
int A;
int B;
String method;
public CalculateRpcRequest(int A, int B, String method) {
this.A=A;
this.B=B;
this.method = method;
}
}
远程Server端:
1、用于反序列化的封装对象
注:Client端与Server端的序列化对象必须保持全类名一致,即包名和类名完全相同才能成功转换反序列化对象。
import java.io.Serializable;
public class CalculateRpcRequest implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
int A;
int B;
String method;
public CalculateRpcRequest(int A, int B, String method) {
this.A=A;
this.B=B;
this.method = method;
}
public int getA() {
return A;
}
public void setA(int a) {
A = a;
}
public int getB() {
return B;
}
public void setB(int b) {
B = b;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
2、远程端计算器接口:
public interface Calculator {
int add(int i, int j);
}
3、远程端计算器实现类:
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
return i+j;
}
}
4、远程端接收Client端请求调用本地方法并返回执行结果
Server端接收Client端请求,获取封装对象属性值,进行本地方法调用并返回执行结果。
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import Test.RPC.consumer.CalculateRpcRequest;
public class Server {
private static Calculator calculator=new CalculatorImpl();
public static void main(String[] args)
{
ServerSocket listener = null;
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
listener = new ServerSocket(9000);
while(true)
{
//监听连接的TCP Client
Socket socket=listener.accept();
//对象输入流,读入Socket中数据反序列化转换为对象
objectInputStream = new ObjectInputStream(socket.getInputStream());
try {
Object object = objectInputStream.readObject();
int result=0;
if(object instanceof CalculateRpcRequest)
{
CalculateRpcRequest calculateRpcRequest=(CalculateRpcRequest)object;
if("add".equals(calculateRpcRequest.getMethod()))
{
result=calculator.add(calculateRpcRequest.getA(), calculateRpcRequest.getB());
}
else
{
throw new UnsupportedOperationException();
}
}
//对象输出流,将封装数据的对象序列化写入Socket
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(new Integer(result));
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
socket.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if(listener!=null)
{
try {
listener.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(objectInputStream!=null)
{
try {
objectInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(objectOutputStream!=null)
{
try {
objectOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
总结
1、示例通过对象序列化基本实现了RPC过程,对于高级RPC框架的服务注册、负载均衡等机制未进行涉及,本文仅供参考。
2、代码引用:http://bridgeforyou.cn/2018/05/04/How-to-Implement-a-Simple-RPC/