1、基于TCP协议的RPC
1.1、RPC名词解释:
RPC(Remote Process Call):远程过程调用。它应用广泛,实现方式也很多,拥有RMI(remote method invocation)、WebService等诸多成熟的方案,在业界得到广泛的应用。
RPC的实现包括客户端和服务端,即服务的调用方和服务的服务方。服务调用方发送RPC请求到服务提供方,服务提供方根据调用方提供的参数执行请求方法,将执行结果返回给调用方,一次RPC调用完成。
1.2、对象序列化:
无论是何种类型的数据,最终都需要转换成二进制流在网络上传输。在面向对象的程序设计中,如何将一个定义好的对象传输到远端呢?数据的发送方需要将对象转换为二进制流,才能在网络上进行传输,而数据的接收方则需要把二进制流转换为对象。
- 将对象转换为二进制流的过程称为对象的序列化。
- 将二进制流恢复为对象的过程称为对象的反序列化。
对象的序列化与反序列化有多种成熟的解决方案,较为常用的有Google的ProtocalBuffers、Java本身内置的序列化方式、Hessian以及JSON和XML等。
这里重点介绍Java内置的序列化方式和基于Java的Hessian序列化方式:
1、Java内置的序列化方式所实现对象序列化和反序列化的关键代码:
//定义一个字节数组输出流
ByteArrayOutputStream os = new ByteArrayOutputStream();
//对象输出流
ObjectOutputStream out = new ObectOutputStream(os);
//将对象写入到字节数组输出,进行序列化
out.writeObject(zhangsan);
byte[] zhangsanByte = os.toByteArray();
//字节数组输入流
ByteArrayInputStream is = new ByteArrayInputStream(zhangsanByte);
//进行反序列化,从流中读取对象
ObjectInputStream in = new ObjectInputStream(is);
Person person = (Person) in.readObject();
通过java.io包下的ObjectOutputStream的writeObject方法,将Person类的实例zhangsan序列化为字节数组,然后再通过ObjectInputStream的readObject方法将字节数组反序列化为person对象。
2、使用Hessian进行序列化,需要引入其提供的三方包Hessian-4.0.7.jar,针对基于java的Hessian的序列化和反序列化的实现:
ByteArrayOutputStream os = new ByteArrayOutputStream();
//Hessian的序列化输出
HessianOutput ho = new HessianOutput(os);
ho.writeObject(zhangsan);
byte[] zhangsanByte = os.toByteArray();
ByteArrayInputStream is = new ByteArrayInputStream(zhangsanByte);
//Hessian的反序列化读取对象
HessianInput hi = new HessianInput(is);
Person person = (Person) hi.readObject();
1.3、基于TCP协议实现RPC:
基于Java的SocketAPI,我们能够实现一个简单的RPC调用,这个例子中包含了服务的接口及接口的远端实现、服务的消费者与远端的提供方。如下图所示:
public interface SayHelloService() {
public String sayHello(String helloArg);
}
服务的实现:
public class SayHelloServiceImpl implements SayHelloService {
@Override
pulbic String sayHello(String helloArg) {
if(helloArg.equals("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 os = new ObjectOutputStream(socket.getOutputStream());
os.writeUTF(interfacename); //接口名称
os.writeUTF(method.getName()); //方法名称
os.writeObject(method.getParameterTypes());
os.writeObject(arguments);
//从远端读取方法执行结果
ObjectInputStream is = new ObjectInputStream(socket.getInputStream);
Object result = is.readObject();
服务提供者Provider类的部分关键代码:
ServerSocket server = new ServerSocket(1234);
while(true) {
Socket socket = server.accept();
//读取服务信息
ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
String interfacename = is.readUTF(); //接口名称
String methodName = is.readUTF(); //方法名称
Class<?>[] parameterTypes = (Class<?>[]) is.readObject(); //参数类型
Object[] arguments = (Object[]) is.readObject(); //参数对象
//执行调用
Class interfacenameclass = Class.forName(interfacename); //得到接口的class
Object service = services.get(interfacename); //取得服务实现的对象
Method method = interfacenameclass.getMethod(methodName,parameterTypes); //获得要调用 的方法
Object result = method.invoke(service,arguments);
ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(result);
}
服务提供端事先将服务实例化好后放在services这个Map中,通过一个while循环,不断的接收新到来的请求,得到所需要的参数,包括接口名称、方法名称、参数类型和参数,通过java的反射取得接口中需要调用的方法,执行后将结果返回给服务的消费者。
2、基于HTTP协议的RPC
2.1、HTTP协议栈:
2.2、HTTP请求与相应:
2.3、通过HttpClient发送HTTP请求:
2.4、使用HTTP协议的优势:
2.5、JSON和XML:
2.6、RESTful和RPC:
2.7、基于HTTP协议的RPC的实现: