RPC框架原理剖析(含实例)(转)
转自:http://blog.csdn.net/rulon147/article/details/53814589
一、什么是RPC
二、图例说明
三、java 实例演示
1、实现技术方案
下面使用比较原始的方案实现RPC框架,采用Socket通信、动态代理与反射与Java原生的序列化。
2、RPC框架架构
RPC架构分为三部分:
- 服务提供者,运行在服务器端,提供服务接口定义与服务实现类。
- 服务中心,运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。
- 服务消费者,运行在客户端,通过远程代理对象调用远程服务。
3、 具体实现
1)服务提供者接口定义与实现,代码如下:
- package services;
- public interface HelloService {
- String sayHi(String name);
- }
2)HelloServices接口实现类:
- package services.impl;
- import services.HelloService;
- public class HelloServiceImpl implements HelloService {
- public String sayHi(String name) {
- return "Hi, " + name;
- }
- }
3)服务中心代码实现,代码如下:
- package services;
- import java.io.IOException;
- public interface Server {
- public void stop();
- public void start() throws IOException;
- public void register(Class serviceInterface, Class impl);
- public boolean isRunning();
- public int getPort();
- }
4)服务中心实现类:
- package services.impl;
- 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;
- import services.Server;
- public class ServiceCenter implements Server {
- private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime()
- .availableProcessors());
- private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();
- private static boolean isRunning = false;
- private static int port;
- public ServiceCenter(int port) {
- this.port = port;
- }
- public void stop() {
- isRunning = false;
- executor.shutdown();
- }
- public void start() throws IOException {
- ServerSocket server = new ServerSocket();
- server.bind(new InetSocketAddress(port));
- System.out.println("start server");
- try {
- while (true) {
- // 1.监听客户端的TCP连接,接到TCP连接后将其封装成task,由线程池执行
- executor.execute(new ServiceTask(server.accept()));
- }
- } finally {
- server.close();
- }
- }
- public void register(Class serviceInterface, Class impl) {
- serviceRegistry.put(serviceInterface.getName(), impl);
- }
- public boolean isRunning() {
- return isRunning;
- }
- public int getPort() {
- return port;
- }
- private static class ServiceTask implements Runnable {
- Socket clent = null;
- public ServiceTask(Socket client) {
- this.clent = client;
- }
- public void run() {
- ObjectInputStream input = null;
- ObjectOutputStream output = null;
- try {
- // 2.将客户端发送的码流反序列化成对象,反射调用服务实现者,获取执行结果
- input = new ObjectInputStream(clent.getInputStream());
- String serviceName = input.readUTF();
- String methodName = input.readUTF();
- Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
- Object[] arguments = (Object[]) input.readObject();
- Class serviceClass = serviceRegistry.get(serviceName);
- if (serviceClass == null) {
- throw new ClassNotFoundException(serviceName + " not found");
- }
- Method method = serviceClass.getMethod(methodName, parameterTypes);
- Object result = method.invoke(serviceClass.newInstance(), arguments);
- // 3.将执行结果反序列化,通过socket发送给客户端
- output = new ObjectOutputStream(clent.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 (clent != null) {
- try {
- clent.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- }
5)客户端的远程代理对象:
- package client;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- import java.lang.reflect.Method;
- public class RPCClient<T> {
- @SuppressWarnings("unchecked")
- public static <T> T getRemoteProxyObj(final Class<?> serviceInterface, final InetSocketAddress addr) {
- // 1.将本地的接口调用转换成JDK的动态代理,在动态代理中实现接口的远程调用
- return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[] { serviceInterface },
- new InvocationHandler() {
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Socket socket = null;
- ObjectOutputStream output = null;
- ObjectInputStream input = null;
- try {
- // 2.创建Socket客户端,根据指定地址连接远程服务提供者
- socket = new Socket();
- socket.connect(addr);
- // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
- output = new ObjectOutputStream(socket.getOutputStream());
- output.writeUTF(serviceInterface.getName());
- output.writeUTF(method.getName());
- output.writeObject(method.getParameterTypes());
- output.writeObject(args);
- // 4.同步阻塞等待服务器返回应答,获取应答后返回
- input = new ObjectInputStream(socket.getInputStream());
- return input.readObject();
- } finally {
- if (socket != null)
- socket.close();
- if (output != null)
- output.close();
- if (input != null)
- input.close();
- }
- }
- });
- }
- }
6)最后为测试类:
- package client;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import services.HelloService;
- import services.Server;
- import services.impl.HelloServiceImpl;
- import services.impl.ServiceCenter;
- public class RPCTest {
- public static void main(String[] args) throws IOException {
- new Thread(new Runnable() {
- public void run() {
- try {
- Server serviceServer = new ServiceCenter(8088);
- serviceServer.register(HelloService.class, HelloServiceImpl.class);
- serviceServer.start();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }).start();
- HelloService service = RPCClient
- .getRemoteProxyObj(HelloService.class, new InetSocketAddress("localhost", 8088));
- System.out.println(service.sayHi("test"));
- }
- }
运行结果:
- regeist service HelloService
- start server
- Hi, test
RPC框架原理剖析(含实例)(转)的更多相关文章
- 一个高性能RPC框架原理剖析
业务与底层网络通信分离 Server大部分主要分为两层: 网络接收层:负责监听端口,负责收包,编码,解码工作,负责将响应包回传给客户端. 业务处理层:负责接收网络接收层完整的包,如果是RPCserve ...
- JQuery数组详解(含实例)
<!doctype html>jQuery数组处理详解(含实例演示)@Mr.Think 演示所用数组 var _mozi=['墨家','墨子','墨翟','兼爱非攻','尚同尚贤']; 1 ...
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除 ...
- 【转】python文件和目录操作方法大全(含实例)
python文件和目录操作方法大全(含实例) 这篇文章主要介绍了python文件和目录的操作方法,简明总结了文件和目录操作中常用的模块.方法,并列举了一个综合实例,需要的朋友可以参考下一.python ...
- mybaits入门(含实例教程和源码) http://blog.csdn.net/u013142781/article/details/50388204
前言:mybatis是一个非常优秀的存储过程和高级映射的优秀持久层框架.大大简化了,数据库操作中的常用操作.下面将介绍mybatis的一些概念和在eclipse上的实际项目搭建使用. 一.mybati ...
- Spring中@Transactional事务回滚(含实例具体解说,附源代码)
一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用. 以下举个栗子:比方一个部门里面有非常多成员,这两者分别保存在部门表和成员表里面,在 ...
- spark 源码分析之十二 -- Spark内置RPC机制剖析之八Spark RPC总结
在spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv中,剖析了NettyRpcEnv的创建过程. Dispatcher.NettyStreamManager.T ...
- 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了
一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...
- Mahout机器学习平台之聚类算法具体剖析(含实例分析)
第一部分: 学习Mahout必需要知道的资料查找技能: 学会查官方帮助文档: 解压用于安装文件(mahout-distribution-0.6.tar.gz),找到例如以下位置.我将该文件解压到win ...
随机推荐
- mysql 数据库简介
1. 什么是数据库 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据. 我们也可以将数据存储在文 ...
- POJ-放苹果(DP)
放苹果 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 29074 Accepted: 18376 Description 把M个 ...
- R数据可视化手册学习简单的绘制常见的图形
1.绘制散点图 # 使用ggplot2 library(ggplot2) ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point() 2.绘制 ...
- (面试)Hash表算法十道海量数据处理面试题
Hash表算法处理海量数据处理面试题 主要针对遇到的海量数据处理问题进行分析,参考互联网上的面试题及相关处理方法,归纳为三种问题 (1)数据量大,内存小情况处理方式(分而治之+Hash映射) (2)判 ...
- CSU 1804 - 有向无环图 - [(类似于)树形DP]
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 ...
- CodeForces - 768C Jon Snow and his Favourite Number 桶排
https://vjudge.net/problem/CodeForces-768C 题意:n个数,k次操作,x.每次操作先排序,再让奇数位置上的数据a[i]:=a[i] XOR x; k< ...
- WordCount优化
Github 地址:chaosrings/wcPro 1.PSP2.1表格 psp 2.1 psp阶段 预估耗时(分钟) 实际耗时(分钟) Planning 计划 10 10 Estimate 估计这 ...
- MySQL 如何删除有外键约束的表数据
今天删除数据库中数据,提示因为设置了foreign key,无法修改删除 可以通过设置FOREIGN_KEY_CHECKS变量来避免这种情况. SET FOREIGN_KEY_CHECKS=0; 删除 ...
- Java学习之路-RMI学习
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远 ...
- 优化dedecms设置文章url自定义规则
DEDECMS自定义URL规则的做得还是不错的,可清楚的看到URL中可用到的变量,并且这些变量包括年月日.时间戳.文章 ID.拼音+文章ID.拼音部首.栏目目录及日期加ID转换的字符串等,基本可以很好 ...