赞
踩
使用 Socket、动态代理、反射 实现一个简易的 RPC 调用
我们前面有一篇 socket 的文章,再之前,还有一篇 java动态代理的文章,本文用到了那两篇文章中的知识点,需要的话可以回顾一下。
下面正文开始:
我们的背景是一个名为cuihua-snack(翠花小吃店)的客户端,要调用cuihua-core(翠花核心厨房)的服务端的接口,要求采用RPC的方式调用。
首先,我们创建两个项目cuihua-snack、cuihua-core
其中,cuihua-core 包含两个模块(关于 maven的模块化开发 可以再去了解一下),core-api中定义了客户端与服务端共同需要的接口和参数;core-service 则是服务端的主要逻辑。
我们有这样一张系统调用关系示意图。
① 服务端启动socket服务;
② 客户端开始调用,通过代理的方式调用;
③ 代理中包含 socket 客户端,与服务端建立连接后,将请求接口的对象信息封装后进行序列化。
④ 服务端接收到 socket 请求后,反序列化拿到请求的对象信息。
⑤ 通过反射,调用接口实现类的方法并返回结果。
⑥ 服务端对执行结果序列化并通过socket 返回给客户端。
⑦ 客户端对服务端返回的数据进行反序列化后,输出。
以上七个步骤,就是整个简易RPC的调用过程。
下面我们来看代码:
首先看 core-api 中的代码:
/**
* 上菜服务
*/
public interface DishService {
String servePickedChineseCabbage(RequestDTO dto);
}
/** * 上菜requestDTO */ @Data public class RequestDTO implements Serializable { /** * 菜量 */ private String quantityType;//big;medium;small; /** * 是否加辣 */ private boolean spicy; /** * 冷热 */ private String coldOrHot;//cold/hot }
/**
* RPC Request
*/
@Data
public class RpcRequest implements Serializable {
private String className;
private String methodName;
private Object[] args;
private Class[] types;
}
再来看 core-service的代码:
public class DishServiceImpl implements DishService {
public String servePickedChineseCabbage(RequestDTO dto) {
System.out.println(dto);
return "Please wait a moment! The dish you want will come soon!";
}
}
public class RpcService { private DishService service; public RpcService(DishService service){ this.service = service; } public void serverRun() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { ServerSocket serverSocket = new ServerSocket(8000); while(true) { Socket socket = serverSocket.accept(); handler(socket); } } private void handler(Socket socket) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException { //读取 socket 传输的数据 ObjectInputStream objectinputstrem = new ObjectInputStream(socket.getInputStream()); RpcRequest rpcRequest = (RpcRequest) objectinputstrem.readObject(); String result = (String) this.invoke(rpcRequest); //将结果写回 socket ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(result); objectOutputStream.flush(); } private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //通过反射进行服务的调用 Class clazz=Class.forName(request.getClassName()); //找到目标方法 Method method=clazz.getMethod(request.getMethodName(),request.getTypes()); return method.invoke(service,request.getArgs()); } }
public class App
{
public static void main( String[] args ) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
DishService dishService = new DishServiceImpl();
RpcService rpcService = new RpcService(dishService);
rpcService.serverRun();
}
}
最后,我们来看 cuihua-snack的代码:
public class CuihuaInvocationHandler implements InvocationHandler { private String host; private int port; public CuihuaInvocationHandler(String host,int port){ this.host = host; this.port = port; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //开启客户端 SocketClient socketClient = new SocketClient(host,port); //请求参数 RpcRequest rpcRequest = new RpcRequest(); rpcRequest.setArgs(args); rpcRequest.setTypes(method.getParameterTypes()); rpcRequest.setClassName(method.getDeclaringClass().getName()); rpcRequest.setMethodName(method.getName()); //发送 Object obj = socketClient.transMessage(rpcRequest); //响应结果 return obj; } }
/**
* 代理服务
*/
public class ProxyDishService {
public <T> T getInstance(Class<T> clazz){
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class<?>[]{clazz},new CuihuaInvocationHandler("localhost",8000));
}
}
public class SocketClient { private String host; private int port; public SocketClient(String host,int port){ this.host = host; this.port = port; } public Socket getSocket() throws IOException { Socket socket = new Socket(host,port); return socket; } public Object transMessage(RpcRequest request){ ObjectOutputStream objectOutputStream = null; ObjectInputStream objectInputStream = null; try { Socket socket = getSocket(); //将RpcRequest 写入到输出流中,通过socket传递给服务端 objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(request); objectOutputStream.flush(); //通过输入流,读取服务端通过socket返回的结果 objectInputStream = new ObjectInputStream(socket.getInputStream()); Object obj = objectInputStream.readObject(); return obj; }catch(Exception e){ e.printStackTrace(); }finally{ try { objectInputStream.close(); objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
public class App
{
public static void main( String[] args )
{
//调用代理
ProxyDishService proxy = new ProxyDishService();
RequestDTO dto = new RequestDTO();
dto.setColdOrHot("hot");
dto.setSpicy(true);
dto.setQuantityType("big");
String responseStr = proxy.getInstance(DishService.class).servePickedChineseCabbage(dto);
System.out.println("响应结果:"+responseStr);
}
}
执行 cuihua-core 中 core-service 下的 App 的main方法,启动 ServerSocket;
然后,执行cuihua-snack 中 App 的 main方法,socket客户端发起调用。
服务端打印日志如下:
RequestDTO(quantityType=big, spicy=true, coldOrHot=hot)
客户端打印日志如下:
响应结果:Please wait a moment! The dish you want will come soon!
以上就是 《使用 Socket和动态代理以及反射 实现一个简易的 RPC 调用》的全部内容,感谢阅读!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。