什麼是RPC框架?
- RPC:remote procedure call 即:遠程過程調用
- 在分佈式架構中離不開服務之間的通信
- 爲了提高服務之間通信的性能:產生了如Dubbo、webservice、Thrift等RPC框架
簡易版RPC框架實現
- 通過實現一個簡易版本的RPC框架,去學習其原理
- 首先我們創建需要一個服務端
服務端實現
- rpc-server:以quickstart的方式快速創建一個maven工程
- 以同樣的方式創建rpc-server-api和rpc-server-provider
- 創建api和provider模塊的作用是在本機模擬服務之間的調用
- rpc-server-api:定義客戶端需要拿到的一些信息,如接口、傳輸對象等打成jar包作爲依賴使用
- rpc-server-provider:服務提供方基於api的實現,提供服務供客戶端進行調用。
- 至此我們的服務端基礎架構就搭建完成了
API實現
- 寫一個簡單的接口
public interface UserService {
String handToUser(String content);
String saveUser(User user);
}
Provider實現
- 依賴api(需要把api打成jar包到本地倉庫)
<dependency>
<groupId>com.self.struggle</groupId>
<artifactId>rpc-server-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 服務簡單實現
public class UserServiceImpl implements UserService {
@Override
public String handToUser(String s) {
return "hi,"+s+".Welcome come!";
}
@Override
public String saveUser(User user) {
return user.toString();
}
}
- 我們的服務端實現是要提供給客戶端調用的,所以我們需要暴露出我們的服務實現
- 提供服務暴露的方法—使用代理的形式暴露服務(基於socket實現)
public class RpcServerProxy {
/** 線程池回顧
* newCached:可緩存地線程池,核心線程數爲0,最大線程數爲 Integer.MAX_VALUE
* 在回收時間內,可以對創建好地線程進行復用
*/
ExecutorService executorService = Executors.newCachedThreadPool();
public void publish(int port) {
ServerSocket serverSocket = null;
try {
// port:通過端口暴露服務
serverSocket = new ServerSocket(port);
// 不斷地接受請求
while (true) {
// 建立socket連接:通過ois oos去處理 accept:阻塞
Socket socket = serverSocket.accept();
// 利用線程池來處理請求 每一個socket交給一個DealRequest:具體地處理邏輯
executorService.execute(new DealRequest(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- DealRequest實現
public class DealRequest implements Runnable {
private Socket socket;
public DealRequest(Socket socket) {
this.socket = socket;
}
/**
* 處理socket連接中地流信息
*/
@Override
public void run() {
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
// 獲取客戶端發送請求中地輸入流
objectInputStream = new ObjectInputStream(socket.getInputStream());
/* 輸入流包含的內容
* 請求的目標類,方法名稱,參數 在 api 中定義一個對象,接收返回信息
*/
// 反序列化過程
RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();
// 通過反射 實現調用
Object result = invoke(rpcRequest);
// 寫入結果
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectInputStream != null) {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(objectOutputStream != null) {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Object invoke(RpcRequest request) throws Exception {
// 反射調用
Object[] params = request.getParams();
Class<?>[] types = new Class[params.length];
for (int i = 0; i < params.length; i++) {
types[i] = params[i].getClass();
}
Class<?> clazz = Class.forName(request.getClassName());
Object obj = clazz.newInstance();
Method method = clazz.getMethod(request.getMethodName(), types);
return method.invoke(obj, params);
}
}
發佈服務
- 在App.java中發佈服務
public class App
{
public static void main( String[] args )
{
RpcServerProxy rpcServerProxy = new RpcServerProxy();
rpcServerProxy.publish(8080);
}
}
- 至此,簡易版的服務端實現完成
客戶端實現
- 客戶端需要去調用服務端
- 通過遠程代理服務調用
代理服務實現
- 通過反射的方式進行調用,具體實現在 RemoteInvocationHandler 中
public class RpcClientProxy {
public Object clientProxy(final Class<?> interfaceCls, final String host, final int port) {
return Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{interfaceCls}, new RemoteInvocationHandler(host, port));
}
}
- RemoteInvocationHandler
- 在invoke方法中構建傳輸對象,由RpcNetTransport發送請求
public class RemoteInvocationHandler implements InvocationHandler {
private String host;
private int port;
public RemoteInvocationHandler(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RpcRequest rpcRequest = new RpcRequest();
rpcRequest.setClassName(method.getDeclaringClass().getName());
rpcRequest.setMethodName(method.getName());
rpcRequest.setParams(args);
// 遠程通信
RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
return rpcNetTransport.send(rpcRequest);
}
}
- RpcNetTransport
public class RpcNetTransport {
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
public Object send(RpcRequest request) {
Socket socket = null;
Object result = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
// 建立連接
socket = new Socket(host, port);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush();
objectInputStream = new ObjectInputStream(socket.getInputStream());
result = objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
服務調用
public class App
{
public static void main( String[] args )
{
UserService userService = (UserService) new RpcClientProxy().clientProxy(UserService.class, "localhost", 8080);
String status = userService.handToUser("你好");
System.out.println("server back:"+status);
}
}
驗證結果
-
客戶端
-
服務端
流程圖
- nexus代表私服倉庫
- ProxyClient:客戶端代理,socket建立連接後,通過動態代理的方式進行遠程調用
- provider:業務邏輯實現,對api進行處理
- RpcproxyServer:服務端代理,暴露服務,供客戶端調用
源碼和升級版本
- https://gitee.com/joyful_live/rpc.git