视频教程地址 DT课堂(原名颜群)

整体思路
RPC(Remote Procedure Call),即远程过程调用。使用RPC,可以像使用本地的程序一样使用远程计算机上的程序。RPC使得开发分布式程序更加容易。下面是一个基于java的简单的RPC实例,有助于学习dubbo或grpc等框架的原理。

原理分析
RPC采用客户机/服务器模式。请求程序就是客户端,而服务提供程序就是服务端。也就是说需要两个角色,服务端和客户端。首先,客户端调用进程发送一个调用信息(调用的接口,方法名,方法传入参数等)给服务端,然后等待应答信息。在服务器端,当一个调用信息到达,服务器获得调用信息并解析执行调用的接口和方法,然后发送调用的方法返回值,然后等待下一个调用信息,最后,客户端接收到服务端发送回来的方法返回信息。

以下是代码
服务端
首先需要业务类,然后需要一个注册中心,注册中心可以把被调用的业务类注册到一个map集合中,然后根据客户端发送过来的调用信息执行相应的业务类对象的方法,并返回方法的返回值
创建需要发布的业务类接口和具体实现类

package org.rpc.service;

public interface HelloService {

	Object sayHello(String name);

}

  

package org.rpc.service;

public class HelloServiceImpl implements HelloService {

	public Object sayHello(String name) {
// TODO Auto-generated method stub
return "hello,"+name;
} }

  

然后是服务端的主体类,就是注册中心。定义三个方法start()初始化方法,stop()停止服务方法,register()注册中心

package org.rpc.service;

public interface Server {

    void start();

    void stop();

    void register(Class service,Class serviceImpl);

}

具体实现类,首先声明一个map集合来来存放业务类,key是业务类的接口名,value是接口对应的具体实现类class对象

package org.rpc.service;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ServerCenter implements Server { private static HashMap<String, Class> serviceRegister=new HashMap<>();
private static int PORT=0;
//根据本地计算机性能生成对应容量的线程池
private static ExecutorService servicePool=
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public ServerCenter() { } public ServerCenter(int port) {
this.PORT=port;
} @Override
public void start() {
ServerSocket server=null;
try {
server=new ServerSocket();
server.bind(new InetSocketAddress(PORT));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(true) {
System.out.println("等待客户端连接...");
Socket socket = null;
try {
//服务器等待连接,每当有客户端连接就开启线程执行调用信息处理类
socket = server.accept();
servicePool.execute(new ServiceTask(socket));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } } @Override
public void stop() { servicePool.shutdown(); } @Override
public void register(Class service, Class serviceImpl) { serviceRegister.put(service.getName(), serviceImpl); } //具体调用信息处理类,解析客户端发来的调用信息并执行对应的业务方法并相应方法的返回值
private class ServiceTask implements Runnable{ private Socket socket=null; public ServiceTask() { } public ServiceTask(Socket socket) {
this.socket = socket;
} @Override
public void run() {
ObjectInputStream ois=null;
ObjectOutputStream oos=null;
try {
System.out.println("客户端已连接");
ois=new ObjectInputStream(socket.getInputStream());
//获取客户端发来的接口名
String className=ois.readUTF();
//获取客户端发来的方法
String methodName=ois.readUTF();
//获取客户端发来的方法参数类型
Class[] methodTypes=(Class[]) ois.readObject();
//获取客户端发来的方法参数值
Object[] args =(Object[]) ois.readObject();
//从map中找到需要的接口并执行客户端调用的方法
Class service=serviceRegister.get(className);
Method method = service.getMethod(methodName,methodTypes);
Object returns = method.invoke(service.newInstance(), args); oos=new ObjectOutputStream(socket.getOutputStream());
//返回方法执行的结果
oos.writeObject(returns); }catch (Exception e) {
e.printStackTrace();
}finally {
try {
//关闭资源
if(oos!=null)oos.close();
if(ois!=null)ois.close();
if(socket!=null)socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

  

客户端

客户端使用动态代理来接受服务端的业务类返回值

package org.rpc.client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket; public class Client { @SuppressWarnings("unchecked")
public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr) { return (T)Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[] {serviceInterface},
new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object[] args){ Socket socket =null;
ObjectInputStream ois=null;
ObjectOutputStream oos=null;
Object result=null; try {
socket=new Socket();
socket.connect(addr); oos=new ObjectOutputStream(socket.getOutputStream());
//发送需要的接口名
oos.writeUTF(serviceInterface.getName());
//发送需要的方法名
oos.writeUTF(method.getName());
//方法参数类型
oos.writeObject(method.getParameterTypes());
//方法参数
oos.writeObject(args); ois=new ObjectInputStream(socket.getInputStream());
result=ois.readObject(); }catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(oos!=null)oos.close();
if(ois!=null)ois.close();
if(socket!=null)socket.close(); } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} return result;
}
});
} }

  

测试

服务端使用register()方法对HelloService类进行注册并开启服务等待客户端连接

package org.rpc.test;

import org.rpc.service.HelloService;
import org.rpc.service.HelloServiceImpl;
import org.rpc.service.Server;
import org.rpc.service.ServerCenter; public class ServerTest { public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Server server = new ServerCenter(9999);
server.register(HelloService.class, HelloServiceImpl.class);
server.start();
}
}).start();
} }

  

  

客户端直接声明需要调用的业务类的接口接受动态代理对象并执行需要的方法

package org.rpc.test;

import java.net.InetSocketAddress;

import org.rpc.client.Client;
import org.rpc.service.HelloService; public class ClientTest { public static void main(String[] args) throws ClassNotFoundException { HelloService hs=Client.getRemoteProxyObj(Class.forName("org.rpc.service.HelloService"), new InetSocketAddress("127.0.0.1", 9999));
System.out.println(hs.sayHello("world")); } }

 

视频教程地址http://aibd.ke.qq.com

自定义RPC框架--基于JAVA实现的更多相关文章

  1. 手写简易版RPC框架基于Socket

    什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...

  2. 简单RPC框架-基于Consul的服务注册与发现

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  3. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  4. GRPC 1.3.4 发布,Google 高性能 RPC 框架(Java C++ Go)

    GRPC 1.3.4 发布了,GRPC 是一个高性能.开源.通用的 RPC 框架,面向移动和 HTTP/2 设计,是由谷歌发布的首款基于 Protocol Buffers 的 RPC 框架. GRPC ...

  5. 完全开源Android网络框架 — 基于JAVA原生的HTTP框架

    HttpNet网络请求框架基于HttpUrlConnection,采用Client + Request + Call的请求模型,支持https默认证书,数字安全证书.支持http代理!后续将会实现队列 ...

  6. 分布式架构探索 - 1. RPC框架之Java原生RMI

    1. 什么是RPC RPC(Remote Procedure Call)即远程过程调用,指的是不同机器间系统方法的调用,这和 同机器动态链接库(DLL)有点类似,只不过RPC是不同机器,通过网络通信来 ...

  7. 遗传算法框架-基于java jenetics库实现

    本篇并非介绍如何从0开始开发遗传算法框架,反而推荐各位使用已有的GA库jenetics来做遗传算法. GA算法的逻辑还是贴下: 好了,下面介绍的是基于jenetics开发的更贴近业务侧的框架,以及使用 ...

  8. 【原创】三分钟教你学会MVC框架——基于java web开发(2)

    没想到我的上一篇博客有这么多人看,还有几位看完之后给我留言加油,不胜感激,备受鼓励,啥都别说了,继续系列文章之第二篇.(如果没看过我第一篇博客的朋友,可以到我的主页上先浏览完再看这篇文章,以免上下文对 ...

  9. 【原创】三分钟教你学会MVC框架——基于java web开发(1)

    MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法. ...

随机推荐

  1. 修改linux服务器的MySQL密码

    1.   首先用管理员权限登陆Linux: 2.   输入:vi  /etc/my.cnf  回车.然后按“i”键盘,在这个文件中的最后一行输入:skip-grant-tables   然后按 esc ...

  2. shutil 拷贝 / 移动 / 压缩 / 解压缩

    # shutil_demo.py 高级文件操作(拷贝 / 移动 / 压缩 / 解压缩) import shutil def shutil_demo(): # 拷贝文件 shutil.copy2('fi ...

  3. bzoj5049: 导航系统

    Description 小Q来到了一个随机的国度.这个国度由n座城市和m条双向道路构成.因为这个国度崇尚随机,因此m条边是用随机 选择两端点的方式生成的.充满好奇的小Q想在这里进行k次随机的旅行,每次 ...

  4. cookie.js插件

    /*! cookiejs v1.0.23 | MIT (c) 2018 kenny wong | https://github.com/jaywcjlove/cookie.js */!function ...

  5. [UE4]Slider

    Slider:滑动条 一.Slider.Bar Thickness:滑动条厚度 二.Slider.Appearance.Step Size:每次滑动的步进值 三.Slider.Appearance.V ...

  6. autofac中文文档

    https://autofaccn.readthedocs.io/zh/latest/index.html

  7. POJ3259 Wormholes

    Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes ...

  8. 第25课 可变参数模板(6)_function_traits和ScopeGuard的实现

    1. function_traits (1)function_traits的作用:获取函数的实际类型.返回值类型.参数个数和具体类型等.它能获取所有函数语义类型信息.可以获取普通函数.函数指针.std ...

  9. mysql相关碎碎念

    取得当天: SELECT curdate(); mysql> SELECT curdate();+------------+| curdate()  |+------------+| 2013- ...

  10. Spring MVC Controller异常处理总结

    在项目开发过程中,经常遇到服务被攻击的情况,虽然接口在设计过程中有相当多的安全措施,例如cookie校验.风控.访问熔断等相关技术保证服务的安全性,不过感觉还是有必要收集分析一下这些攻击请求者,以备为 ...