使用Java语言的Socket API,我们能够实现一个简单的RPC调用,在这个例子中,包括了服务的接口及接口的远端实现、服务的消费者与远端的提供方。基于TCP协议所实现的RPC的类图:
1463890335757166139.jpg
服务的接口和实现都非常简单,它提供了一个SayHello方法,它有一个String类型的参数,通过该参数来识别究竟是返回hello还是返回byebye,代码如下:
pulic interface SayHelloService {
/**
*问好的接口
*@param helloArg 参数
*@retrun
*/
public String sayHello(String helloArg);
}
服务的实现:
public class SayHelloServiceImpl implements SayHelloService {
@Override
public String sayHello(String helloArg) {
if(helloArg.equls("hello")) {
return "hello";
} else {
return "bye bye";
}
}
}
服务消费者Consumer类的部分关键代码:
//接口名称
String interfacename = SayHelloService.class.getName();
//需要远程执行的方法
Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class);
//需要传递到远端的参数
Object[] arguments = {"hello"};
Socket socket = new Socket("127.0.0.1", 1234);
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(interfacename); //接口名称
output.writeUTF(method.getName()); //方法名称
output.writeObject(method.getParameterTypes());
output.writeObject(arguments);
//从远端读取方法执行结果
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject();
先取得接口的名称、需求调用的方法和需要传递的参数,并通过Socket将其发送到服务提供方,等待服务端响应结果。此处为了便于演示,使用的是阻塞式I/O,实际的生产环境中出于性能考虑,往往使用非阻塞式I/O,以提高更大的吞吐量。
服务提供者Provider类的部分关键代码:
ServiceSocket server = new ServiceSocket(1234);
while(true) {
Socket socket = service.accept();
//读取服务信息
ObjectInputStream input = new ObjectInputStream(scoket.getInputStream());
String interfacename = input.readUTF(); //接口名称
String methodName = input.readUTF(); //方法名称
Class>[] parameterTypes = (Class>[])input.readObject(); //参数类型
Object[] arguments = (Object[])input.readObject(); //参数对象
//执行调用
Class serviceinterfaceclass = Class.forName(interfacename); //得到接口的class
Object service services.get(interfacename); //得到服务实现的对象
Method method = serviceinterfaceclass.getMethod(methodName, parameterTypes);//获得要调用的方法
Object result = method.invoke(service, arguments);
ObjectOutputString output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(result);
}
服务提供端事先将服务实例化好后房租service这个Map中(此次涉及服务的路由,被简化了,在以后的文章中会做出说明),通过一个while循环,不断地接收新到来的请求,得到所需要的参数,包括接口名称、方法名称、参数类型和参数,通过java的反射取得接口中需求调用的方法,执行后将结果返回给服务的消费者。
在真实的生产环境中,常常是多个客服端同时发送多个请求道服务器,服务端则需要实现同时接收和处理多个客服端的请求,涉及并发处理、服务路由、复杂均衡等。