什麼是PRC
PRC是一種遠程過程調用協議,可以像調用本地服務一樣調用遠程的服務,是一種採用客戶端/服務器的模式。常見的PRC框架也有很多比如最常用的dubbo等。
RPC能夠讓本地應用簡單、高效地調用遠程服務器中的服務。它主要應用在分佈式系統、微服務。
代碼實例
技術點:Java socket、動態代理、Java對象操作流、反射
接口以及接口實現
/**
* Created by IntelliJ IDEA.
* 服務類接口
*/
public interface IService {
String getTest(String string);
}
/**
* Created by IntelliJ IDEA.
* 服務接口的實現類
*/
public class ServiceImpl implements IService {
@Override
public String getTest(String string) {
return "調用成功了: " + string;
}
}
/**
* Created by IntelliJ IDEA.
*/
public interface ILoginService {
String login(String string);
}
/**
* Created by IntelliJ IDEA.
*/
public class LoginServiceImpl implements ILoginService {
@Override
public String login(String string) {
return string;
}
}
服務端服務註冊實例
/**
* Created by IntelliJ IDEA.
* 服務端
*/
public class RpcServer {
private static final HashMap<String, Class<?>> SERVER_MAP = new HashMap<>();
private int port;
public RpcServer(int port) {
this.port = port;
}
/**
* serviceInterface : 接口
* impl:接口實現類
* 將接口服務放到一個HashMap集合中
*/
public RpcServer register(HashMap<Class<?>, Class<?>> hashMap) {
hashMap.forEach((key, value) -> SERVER_MAP.put(key.getName(), value));
return this;
}
/**
* 執行等待
*
*/
public void run() throws IOException {
ServerSocket server = new ServerSocket();
/*打開服務端並設置端口爲port*/
server.bind(new InetSocketAddress(port));
/*對象輸入流*/
ObjectInputStream input = null;
/*對象輸出流*/
ObjectOutputStream output = null;
Socket socket = null;
try {
while (true) {
/*開始接收 線程會進行等待*/
socket = server.accept();
/*輸入流 獲取到客戶端發送來的消息*/
input = new ObjectInputStream(socket.getInputStream());
String serviceName = input.readUTF();
System.out.println("服務名稱:" + serviceName);
String methodName = input.readUTF();
System.out.println("服務方法" + methodName);
/*服務的參數列表*/
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
/*接口的Class*/
Object[] arguments = (Object[]) input.readObject();
/*根據服務名稱得到該服務的實現類*/
Class serviceClass = SERVER_MAP.get(serviceName);
if (serviceClass == null) {
throw new ClassNotFoundException(serviceName + " not found");
}
/*得到方法*/
Method method = serviceClass.getMethod(methodName, parameterTypes);
/*相當於接口回調*/
Object result = method.invoke(serviceClass.newInstance(), arguments);
/*輸出流*/
output = new ObjectOutputStream(socket.getOutputStream());
/*發送*/
output.writeObject(result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
HashMap<Class<?>, Class<?>> hashMap = new HashMap<>();
hashMap.put(IService.class, ServiceImpl.class);
hashMap.put(ILoginService.class, LoginServiceImpl.class);
/*服務端開始註冊服務*/
new RpcServer(7777).register(hashMap).run();
}
}
客戶端服務調用實例
/**
* Created by IntelliJ IDEA.
* 動態代理
* 客戶端調用服務
*/
public class RpcClient<T> implements InvocationHandler {
private Class<T> serviceInterface;
private InetSocketAddress addr;
/**
* serviceInterface:遠程服務接口
* ip:遠程IP地址
* port:遠程端口
*/
public RpcClient(Class<T> serviceInterface, String ip, String port) {
this.serviceInterface = serviceInterface;
this.addr = new InetSocketAddress(ip, Integer.parseInt(port));
}
public T getClientIntance() {
/*傳入被代理的類*/
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
try {
/*創建Socket客戶端,根據指定地址連接遠程服務提供者*/
socket = new Socket();
/*連接服務端*/
socket.connect(addr);
/*將遠程服務調用所需的接口類、方法名、參數列表等編碼後發送給服務提供者*/
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceInterface.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
/*同步阻塞等待服務器返回應答,獲取應答後返回*/
input = new ObjectInputStream(socket.getInputStream());
/*返回結果*/
return input.readObject();
} finally {
if (socket != null) {
socket.close();
}
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
}
}
public static void main(String[] args) {
RpcClient client = new RpcClient<>(IService.class, "localhost", "7777");
IService hello = (IService) client.getClientIntance();
/*調用成功 打印返回值*/
System.out.println(hello.getTest("RPC"));
RpcClient loginPrcClient = new RpcClient<>(ILoginService.class, "localhost", "7777");
ILoginService iLoginService = (ILoginService) loginPrcClient.getClientIntance();
/*調用成功 打印返回值*/
System.out.println(iLoginService.login("登錄成功了"));
}
}
實例執行結果
服務端執行進入等待
客戶端執行
再看服務端變化