RPC,远程过程调用,顾名思义,在远方有个服务,你该怎么调用它?
这个问题的解决核心是先解决网络通讯问题,我得能访问到,其次解决调用问题。
这么多年以来,网络通讯的实现方案有很多,简单列举如下:
目前来说,主流的还是RestFul 和 RPC,各有各的优缺点,比如能否跨越防火墙,性能高低啊,当然TCP虽然写着麻烦,但是优点多多
网络通讯势必避免不了序列化问题,那么常见的序列化框架如下:
基于性能体积等考虑,比较推荐的是google protobuf和facebook Thrift
下面是一个最简单的RPC实现,里面的序列化方案使用最原始的JDK的序列化,实际使用过程中更换
//Server
public class Server {
public static boolean running = true;
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9000);
while(running){
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception {
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
ObjectInputStream ois = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out);
//接收客户端发送过来的方法详情,通过反射调用相关方法,并返回客户端数据
String className = ois.readUTF();
String methodName = ois.readUTF();
Class[] parameterTypes = (Class[]) ois.readObject();
Object[] args = (Object[]) ois.readObject();
//根据接口类名找到接口同目录下实现该接口的所有类,这里也可以通过Spring @Autowired 去注入一个具体类对象
Class clazz = Class.forName(className);
List<Class<?>> allClassByInterface = ClassUtils.getAllClassByInterface(clazz);
Class clazz2 = allClassByInterface.get(0);
Method method = clazz2.getMethod(methodName, parameterTypes);
Object o = method.invoke(clazz2.newInstance(), args);
oos.writeObject(o);
oos.flush();
}
}
//client
public class Client {
public static void main(String[] args) throws IOException {
System.out.println("我是demo06 的client");
IUserService service = (IUserService)Stub.getStub(IUserService.class);
System.out.println(service.findUserById(123));
}
}
//stub
public class Stub {
public static Object getStub(final Class clazz){
/*
proxy: 代理的对象
method: 代理的对象正在执行的方法
args: 方法的参数
*/
InvocationHandler h = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.建立连接
Socket socket = new Socket("localhost", 9000);
//2.往Server端写数据
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
String clazzName = clazz.getName();
String methodName = method.getName();
//为了避免方法重载,把方法的参数类型传递给server
Class<?>[] parameterTypes = method.getParameterTypes();
oos.writeUTF(clazzName);
oos.writeUTF(methodName);
oos.writeObject(parameterTypes);
oos.writeObject(args);
oos.flush();
//3.从Server端读数据
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object o = ois.readObject();
oos.close();
socket.close();
return o;
}
};
/*
Proxy.newProxyInstance :new出来一个代理类对象
IUserService.class.getClassLoader() :产生代理类的class loader
new Class[]{IUserService.class} : 这个代理类实现了哪些接口
h;调用动态代理类方法的处理器,h 实例化的时候(上面代码),invoke方法在动态代理类的所有方法执行的时候都会执行
*/
Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);
//通过反射可以看看这个代理类的相关信息
System.out.println(o.getClass().getName());
System.out.println(o.getClass().getInterfaces()[0]);
return o;
}
}
原文:https://www.cnblogs.com/zhenhunfan2/p/14648909.html