自己实现一次Java的rpc调用
自己实现一次
RPC
其实并不难,只需要略懂点Socket
编程,和Proxy
动态代理
公共类
公共的服务接口
public interface FooService {
String foo(String string);
}
自定义关于远程调用的方法描述类
import java.io.Serializable;
public class TargetMethod implements Serializable {
private static final long serialVersionUID = -7542219517072936368L;
//调用的方法名称
private String methodName;
//参数列表
private Object[] params;
//参数的类型列表
private Class<?>[] paramsClass;
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
this.paramsClass = new Class<?>[params.length];
for (int x = 0; x < params.length; x++) {
paramsClass[x] = params[x].getClass();
}
}
public Class<?>[] getParamsClass() {
return paramsClass;
}
public void setParamsClass(Class<?>[] paramsClass) {
this.paramsClass = paramsClass;
}
}
服务提供者
FooService
的实现类
public class FooServiceImpl implements FooService {
@Override
public String foo(String string) {
return "Hello," + string;
}
}
对外暴露服务
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Provider {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//服务的实现
FooServiceImpl fooServiceImpl = new FooServiceImpl();
//在1024端口暴露服务
try (ServerSocket serverSocket = new ServerSocket(1024)) {
while (true) {
Socket socket = serverSocket.accept();
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
//读取方法描述,并且通过反射执行方法
TargetMethod targetMethod = (TargetMethod) objectInputStream.readObject();
Method method = fooServiceImpl.getClass().getDeclaredMethod(targetMethod.getMethodName(), targetMethod.getParamsClass());
Object result = method.invoke(fooServiceImpl, targetMethod.getParams());
//往客户端写入执行结果
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
socket.shutdownOutput();
}
}
}
}
服务消费者
代理对象生成工厂
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class ProxyFactory {
/**
* 生成一个rpc的代理对象
* @param clazz
* @return
*/
public static FooService getProxy(Class<? super FooService> clazz) {
return (FooService) Proxy.newProxyInstance(ProxyFactory.class.getClassLoader(), new Class<?>[] {clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try(Socket socket = new Socket("127.0.0.1",1024)){
//创建方法描述。写入当前执行的方法名称,参数
TargetMethod targetMethod = new TargetMethod();
targetMethod.setMethodName(method.getName());
targetMethod.setParams(args);
//写入到消费服务者,执行远程调用
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(targetMethod);
objectOutputStream.flush();
socket.shutdownOutput();
//获取到执行结果
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object result = objectInputStream.readObject();
socket.close();
return result;
}
}
});
}
}
远程调用服务
public class Customer {
public static void main(String[] args) {
FooService fooService = ProxyFactory.getProxy(FooService.class);
//执行代理方法,把参数提交给远程服务器完成计算后返回计算结果
String result = fooService.foo("KevinBlandy");
System.out.println(result); //Hello,KevinBlandy
}
}
总结
- 把本地的方法的参数,名称等等封装为对象,序列化位字节数据提交给远程服务器
- 远程服务器读取到参数名称,参数等等数据,在本地反射执行实现实现类的方法,并且通过网络返回计算后的结果
- 必须先启动
服务提供者
,再执行远程调用