先看代码
服务接口
public interface SayHelloService {
String sayHello(String hello);
}
作为服务提供方,要对服务接口给出实现
public class SayHelloServiceImpl implements SayHelloService {
@Override
public String sayHello(String hello) {
if ("hello".equals(hello)) {
return "hello";
} else {
return "bye bye";
}
}
}
消费者代码,很简单,先与本地的8888端口建立一个TCP连接,然后获取输出流,向另一端发送一些数据,这里的另一端就是我们的提供方了。
public class Consumer {
public static void main(String[] args) throws Exception {
String interfaceName = SayHelloService.class.getName();
Method method = SayHelloService.class.getMethod("sayHello", String.class);
Object[] arguments = {"hello"};
// 将调用接口名、方法名、方法形参、方法实参传到另一端
Socket socket = new Socket("localhost", 8888);
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.writeUTF(interfaceName);
outputStream.writeUTF(method.getName());
outputStream.writeObject(method.getParameterTypes());
outputStream.writeObject(arguments);
// 从另一端读取方法执行结果
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject();
System.out.println(result);
}
}
服务提供方监听端口,建立和远端的TCP连接,接收数据,进行处理
public class Producer {
private static final Map<String, Object> SERVICE_INSTANCE_MAP = new HashMap<>();
static {
SERVICE_INSTANCE_MAP.put(SayHelloService.class.getName(), new SayHelloServiceImpl());
}
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(8888);
while (true) {
Socket accept = server.accept();
// 获取远端传来的接口名、方法名、方法形参、方法实参
ObjectInputStream inputStream = new ObjectInputStream(accept.getInputStream());
String interfaceName = inputStream.readUTF();
String methodName = inputStream.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();
Object[] arguements = (Object[]) inputStream.readObject();
// 通过接口名获取JVM中的Class对象
Class<?> serviceInterfaceClass = Class.forName(interfaceName);
// 获取接口实现的实例对象
Object instance = SERVICE_INSTANCE_MAP.get(interfaceName);
// 获取要执行的方法
Method method = serviceInterfaceClass.getMethod(methodName, parameterTypes);
// 执行
Object result = method.invoke(instance, arguements);
// 给远端返回接口
ObjectOutputStream outputStream = new ObjectOutputStream(accept.getOutputStream());
outputStream.writeObject(result);
}
}
}
测试:先启动Producer,再启动Consumer,Consumer的控制台可以看到打印结果
好,现在我们回顾一下整个流程。所谓RPC,远程过程调用,其实就是两台机器之间的两个JVM进程进行通信,我们这里使用TCP建立连接,连接建立好就可以相互发送数据了。
同一个JVM进程内的方法调用一般有两种,一种是调用类的静态方法,一种是调用实例对象的普通方法,但不管是哪种调用方式,我们使用的都是JVM可以处理的对象。而在网络中传输的是二进制流,1001000这种形式的,JVM是不认识的,服务提供方就要通过一些手段将这些二进制数据还原为JVM可以认识的对象然后再进行处理,服务提供方将二进制流还原为对象的过程就是反序列化。消费者需要将对象转换为二进制流在网络中传输,这个过程就是序列化。序列化和反序列化的本质和作用这就清楚了。
服务提供方再利用反射执行方法的调用,然后再将执行结果序列化返回给消费者,消费者再反序列化获取到执行结果打印出来,我们就用最简单的方式实现了一个RPC调用。