概述
Java简单实现RPC原理
RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点(A)通过网络向另一个节点(B)请求服务
实现的基本思路
首先,我们需要一个Client端(A节点)和一个Server端(B节点)进行远程的通信
其次,我们需要在两个节点建立统一的接口(相当于约定好,我们需要生产哪些方法和消费哪些方法)
然后,我们需要利用流完成对象在网络中的序列化和反序列化,以及利用反射技术(最重要的)完成对方法的调用
最后,特别感谢马士兵老师对RPC的讲解。
现在就让我们动手做起来
项目结构
各模块结构
1.模块rpcApi
定义了接口
实体类
/**
* @description: User
* @author: dyy
* @date: 2020/7/7 23:04
* @Version: 1.0
*/
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String address;
public User(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public User(){
}
}
接口代码
/**
* @description: IUserService
* @author: dyy
* @date: 2020/7/7 23:05
* @Version: 1.0
*/
public interface IUserService {
/**
* 根据ID查询User
* @param id
* @return
*/
User findUserById(int id);
/**
* 修改客户信息
* @param name
* @return
*/
User updateUserById(String name);
}
2.模块rpcServer
通过网络对外提供服务
maven 只依赖了接口
mapper.properties文件
这里应该是访问数据库进行增删改查,为了简化问题只做简单实现
/**
* @description: Server端实现接口
* @author: dyy
* @date: 2020/7/7 23:10
* @Version: 1.0
*/
public class UserServiceImpl implements IUserService {
@Override
public User findUserById(int id) {
return new User("小明",id,"");
}
@Override
public User updateUserById(String name) {
return new User(name,101,"");
}
}
对外提供网络服务类
/**
* @description:
* @author: dyy
* @date: 2020/7/7 23:14
* @Version: 1.0
*/
public class NetService {
/**
* mapper维护了服务端提供接口访问的实现类映射
* 例如 com.dyy.api.IUserService=com.dyy.service.UserServiceImpl
* 当我们从网络中获取需要访问的接口时,根据映射关系找到对应实现类
*/
private static Properties mapper = new Properties();;
static{
try (InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("mapper.properties")){
if( null != in && in.available() > 0){
mapper.load(in);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void startService()throws Exception{
System.out.println("启动服务");
try(
//对外提供8888端口服务
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
//获取网络输入流
InputStream in = socket.getInputStream();
//ObjectOutputStream ObjectInputStream 序列化和反序列化的效率不高,后期可优化
ObjectInputStream ois = new ObjectInputStream(in);
//获取网络输入流
OutputStream out = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
){
System.out.println("服务接收请求");
//获取类名
String clazzName = ois.readUTF();
/**
* 因为重载的存在,
* 所以使用反射时,需要知道方法名称和参数类型
*/
//获取方法名
String methodName = ois.readUTF();
//获取方法参数类型
Class<?>[] parameterTypes = (Class<?>[]) ois.readObject();
//获取方法实参
Object[] args = (Object[]) ois.readObject();
//获取接口与实现类的映射关系
clazzName = mapper.getProperty(clazzName);
Class clazz = Class.forName(clazzName);
Method method = clazz.getMethod(methodName, parameterTypes);
//方法调用
Object object = method.invoke(clazz.newInstance(), args);
//写出返回值
oos.writeObject(object);
oos.flush();
System.out.println("服务完成");
}
}
public static void main(String[] args) throws Exception {
//启动服务
startService();
}
}
3.模块rpcClient
通过调用接口完成远程访问请求服务
maven 只依赖了接口
模块结构如下:
Stub类封装了网络通信和调用的接口细节
/**
* @description:
* @author: dyy
* @date: 2020/7/7 23:30
* @Version: 1.0
*/
public class Stub {
public static <T> T getStub(Class<?>... interfaces) {
return (T)Proxy.newProxyInstance(
Stub.class.getClassLoader(),interfaces
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
String clazzName = method.getDeclaringClass().getName();
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
try(
//向远程请求连接
Socket socket = new Socket("127.0.0.1", 8888);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
InputStream in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
){
//发送接口名称
oos.writeUTF(clazzName);
//发送方法名称
oos.writeUTF(methodName);
//发送方法形参类型列表
oos.writeObject(parameterTypes);
//发送方法实参
oos.writeObject(args);
oos.flush();
//读取远程返回的数据
return ois.readObject();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
);
}
}
Client调用接口抽象方法,具体如何做交给Stub中间件完成
/**
* @description:
* @author: dyy
* @date: 2020/7/8 9:55
* @Version: 1.0
*/
public class Client {
public static void main(String[] args) {
IUserService service = Stub.getStub(IUserService.class);
User user = service.updateUserById("大牛");
System.out.println(user);
}
}
程序演示:
最后
以上就是懦弱毛豆为你收集整理的Java简单实现RPC原理Java简单实现RPC原理的全部内容,希望文章能够帮你解决Java简单实现RPC原理Java简单实现RPC原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复