大数据入门第四天——基础部分之轻量级RPC框架的开发
一、概述
、掌握RPC原理
、掌握nio操作
、掌握netty简单的api
、掌握自定义RPC框架
主要内容
1.RPC是什么
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
// 来自百度百科
更加通俗一些的RPC的解释与介绍,参考:https://www.zhihu.com/question/25536695
TCP传输控制协议的通俗解释,参考这里,术语式的解释,参考这里
2.自定义RPC框架思路图解

二、先导知识准备
由上图可以知道,需要自定义RPC框架,需要的知识主要有:spring,socket(由nio为原理的netty替代),动态代理等
1.nio先导知识
参考基础随笔篇:http://www.cnblogs.com/jiangbei/p/7499444.html
2.nio框架——netty
netty推荐书籍:netty权威指南
netty是什么?
是一个网络编程框架(就是一个封装了NIO的框架)
Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.
netty起步
由于暂时不对netty进行深入了解(后续应该会专门有针对netty的随笔),这里仅作到“能用”,点击查看:get started
依赖:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.24.Final</version>
</dependency>
//如果不使用maven,请去maven仓库下载jar即可!
模板代码:
package cn.itcast_03_netty.sendstring.client; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import java.net.InetSocketAddress; import cn.itcast_03_netty.sendobject.coder.PersonEncoder; /**
* • 连接服务器 • 写数据到服务器 • 等待接受服务器返回相同的数据 • 关闭连接
*
* @author wilson
*
*/
public class EchoClient { private final String host;
private final int port; public EchoClient(String host, int port) {
this.host = host;
this.port = port;
} public void start() throws Exception {
EventLoopGroup nioEventLoopGroup = null;
try {
// 客户端引导类
Bootstrap bootstrap = new Bootstrap();
// EventLoopGroup可以理解为是一个线程池,这个线程池用来处理连接、接受数据、发送数据
nioEventLoopGroup = new NioEventLoopGroup();
bootstrap.group(nioEventLoopGroup)//多线程处理
.channel(NioSocketChannel.class)//指定通道类型为NioServerSocketChannel,一种异步模式,OIO阻塞模式为OioServerSocketChannel
.remoteAddress(new InetSocketAddress(host, port))//地址
.handler(new ChannelInitializer<SocketChannel>() {//业务处理类
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new EchoClientHandler());//注册handler
}
});
// 链接服务器
ChannelFuture channelFuture = bootstrap.connect().sync();
channelFuture.channel().closeFuture().sync();
} finally {
nioEventLoopGroup.shutdownGracefully().sync();
}
} public static void main(String[] args) throws Exception {
new EchoClient("localhost", 20000).start();
}
}
EchoClient
package cn.itcast_03_netty.sendstring.client; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import cn.itcast_03_netty.sendobject.bean.Person; public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
// 客户端连接服务器后被调用
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端连接服务器,开始发送数据……");
byte[] req = "QUERY TIME ORDER".getBytes();//消息
ByteBuf firstMessage = Unpooled.buffer(req.length);//发送类
firstMessage.writeBytes(req);//发送
ctx.writeAndFlush(firstMessage);//flush
} // • 从服务器接收到数据后调用
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
throws Exception {
System.out.println("client 读取server数据..");
// 服务端返回消息后
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("服务端数据为 :" + body);
} // • 发生异常时被调用
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
System.out.println("client exceptionCaught..");
// 释放资源
ctx.close();
}
}
EchoClientHandler
package cn.itcast_03_netty.sendstring.server; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import cn.itcast_03_netty.sendobject.coder.PersonDecoder; /**
* • 配置服务器功能,如线程、端口 • 实现服务器处理程序,它包含业务逻辑,决定当有一个请求连接或接收数据时该做什么
*
* @author wilson
*
*/
public class EchoServer { private final int port; public EchoServer(int port) {
this.port = port;
} public void start() throws Exception {
EventLoopGroup eventLoopGroup = null;
try {
//server端引导类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//连接池处理数据
eventLoopGroup = new NioEventLoopGroup();
//装配bootstrap
serverBootstrap.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)//指定通道类型为NioServerSocketChannel,一种异步模式,OIO阻塞模式为OioServerSocketChannel
.localAddress("localhost",port)//设置InetSocketAddress让服务器监听某个端口已等待客户端连接。
.childHandler(new ChannelInitializer<Channel>() {//设置childHandler执行所有的连接请求
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new EchoServerHandler());//注册handler
}
});
// 最后绑定服务器等待直到绑定完成,调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭,因为使用sync(),所以关闭操作也会被阻塞。
ChannelFuture channelFuture = serverBootstrap.bind().sync();
System.out.println("开始监听,端口为:" + channelFuture.channel().localAddress());
channelFuture.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully().sync();
}
} public static void main(String[] args) throws Exception {
new EchoServer(20000).start();
}
}
EchoServer
package cn.itcast_03_netty.sendstring.server; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import java.util.Date; import cn.itcast_03_netty.sendobject.bean.Person; public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("server 读取数据……");
//读取数据
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("接收客户端数据:" + body);
//向客户端写数据
System.out.println("server向client发送数据");
String currentTime = new Date(System.currentTimeMillis()).toString();
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp); } @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server 读取数据完毕..");
ctx.flush();//刷新后才将数据发出到SocketChannel
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
} }
EchoServerHandler
以上就是发送字符串的模板代码,基本上,总体的架构都不需要进行改动,只需要根据业务逻辑调整handler的代码即可!
接下来介绍多个handler的处理方式:
Handler在netty中,无疑占据着非常重要的地位。Handler与Servlet中的filter很像,
通过Handler可以完成通讯报文的解码编码、拦截指定的报文、
统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的。 Netty中的所有handler都实现自ChannelHandler接口。按照输出输出来分,
分为ChannelInboundHandler、ChannelOutboundHandler两大类。
ChannelInboundHandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;
ChannelOutboundHandler对从服务器发往客户端的报文进行处理,
一般用来进行编码、发送报文到客户端。 Netty中,可以注册多个handler。ChannelInboundHandler按照注册的先后顺序执行;
ChannelOutboundHandler按照注册的先后顺序逆序执行,
给出handler的顺序的结论:
多个IN OUT的handler的时候,最后一个addList必须是OUT,而且处理顺序为先IN 的正序以及后OUT的逆序!
1、ChannelInboundHandler之间的传递,通过调用 ctx.fireChannelRead(msg) 实现;
调用ctx.write(msg) 将传递到ChannelOutboundHandler。
2、ctx.write()方法执行后,需要调用flush()方法才能令它立即执行。
3、流水线pipeline中outhandler不能放在最后,否则不生效
4、Handler的消费处理放在最后一个处理。
使用POJO代替上文中的string也是本质上相同的,故这里不再赘述,完整的代码,请查看这里,更多概念与示例,可以参见网友随笔
3.Spring的IOC与AOP
参考之前随笔:http://www.cnblogs.com/jiangbei/p/6790251.html
spring的自定义注解的扫描读取参考Java基础注解部分
三、自定义RPC框架
整个框架架构如下:

//其实dubbo也有这个功能...
由于源码比较多,这里给出下载地址:https://pan.baidu.com/s/1htQcnEs
其余相关后续补充
四、JVM技术
1.JVM内存模型
参考基础篇:http://www.cnblogs.com/jiangbei/p/7813748.html
:https://www.cnblogs.com/peak-c/p/6647381.html
推荐阅读:深入理解JVM虚拟机
可视化工具jconsole的使用:https://www.cnblogs.com/tina-smile/p/5327057.html
https://www.cnblogs.com/baihuitestsoftware/articles/6405580.html
VisualVM的使用待补充
五、hadoop中的RPC框架封装
详细讲解,参考:https://www.cnblogs.com/edisonchou/p/4285817.html
参考:https://www.cnblogs.com/junneyang/p/5841135.
大数据入门第四天——基础部分之轻量级RPC框架的开发的更多相关文章
- 大数据入门第三天——基础补充与ActiveMQ
一.多线程基础回顾 先导知识在基础随笔篇:http://www.cnblogs.com/jiangbei/p/6664555.html 以下此部分以补充为主 1.概念 进程:进行中的程序,内存中有独立 ...
- 大数据入门第十七天——storm上游数据源 之kafka详解(一)入门与集群安装
一.概述 1.kafka是什么 根据标题可以有个概念:kafka是storm的上游数据源之一,也是一对经典的组合,就像郭德纲和于谦 根据官网:http://kafka.apache.org/intro ...
- 大数据入门第二十天——scala入门(一)入门与配置
一.概述 1.什么是scala Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性.Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序. ...
- 大数据入门第十九天——推荐系统与mahout(一)入门与概述
一.推荐系统概述 为了解决信息过载和用户无明确需求的问题,找到用户感兴趣的物品,才有了个性化推荐系统.其实,解决信息过载的问题,代表性的解决方案是分类目录和搜索引擎,如hao123,电商首页的分类目录 ...
- 大数据入门第五天——离线计算之hadoop(上)概述与集群安装
一.概述 根据之前的凡技术必登其官网的原则,我们当然先得找到它的官网:http://hadoop.apache.org/ 1.什么是hadoop 先看官网介绍: The Apache™ Hadoop® ...
- 大数据入门第十七天——storm上游数据源 之kafka详解(三)其他问题
一.kafka文件存储机制 1.topic存储 在Kafka文件存储中,同一个topic下有多个不同partition,每个partition为一个目录,partiton命名规则为topic名称+有序 ...
- 大数据入门第二十一天——scala入门(二)并发编程Akka
一.概述 1.什么是akka Akka基于Actor模型,提供了一个用于构建可扩展的(Scalable).弹性的(Resilient).快速响应的(Responsive)应用程序的平台. 更多入门的基 ...
- 大数据入门第二十天——scala入门(二)scala基础02
一. 类.对象.继承.特质 1.类 Scala的类与Java.C++的类比起来更简洁 定义: package com.jiangbei //在Scala中,类并不用声明为public. //Scala ...
- 大数据入门第二十天——scala入门(二)scala基础01
一.基础语法 1.变量类型 // 上表中列出的数据类型都是对象,也就是说scala没有java中的原生类型.在scala是可以对数字等基础类型调用方法的. 2.变量声明——能用val的尽量使用val! ...
随机推荐
- 用unescape反编码得出汉字
var p="",s="4e00"; for( var i=0;i<255;i++){ p+=unescape(("\\u"+s).r ...
- 在 Linux 上创建虚拟机规模集和部署高度可用的应用
利用虚拟机规模集,可以部署和管理一组相同的.自动缩放的虚拟机. 可以手动缩放规模集中的 VM 数,也可以定义规则,以便根据资源使用情况(如 CPU 使用率.内存需求或网络流量)进行自动缩放. 在本教程 ...
- Linux 系统开机自启的配置文件
程序开机启动的配置文件(/etc/rc.local) # 系统级别 ntsysv # 图形界面设置自启程序 chkconfig(/etc/init.d/sshd) 处理开机启动的文件 # 用户级别 # ...
- Unity调用安卓中的方法遇到的问题
最近在用U3D做一个简单的迷宫游戏,在项目中利用Unity制作游戏场景,在android中调用游戏场景,并在游戏结束后调用安卓方法,传递参数,退出游戏场景 查找网上资料,基本上Unity调用安卓的写法 ...
- 安装zabbix3.4的过程(一)
目录 zabbix服务端安装(centos7.4) zabbix客户端安装 (centos6.9) 注释:本次安装为官方推荐的yum安装方式,如果需要编译安装,请查看下边的博文: 博文地址:https ...
- sql server 使用链接服务器连接Oracle,openquery查询数据
对接问题描述:不知道正式库oracle数据库账户密码,对方愿意在对方的客户端上输入账号和密码,但不告诉我们 解决方案:使用一台sql server作为中间服务器,可以通过转存数据到sql serv ...
- bootstrap-multiselect样式修改
问题 bootstrap-multiselect是一款相当不错的bootstrap风格下拉框组件,但是它的某些样式我不是很喜欢,按钮文本和下拉符号 “” 都是居中的,且下拉列表的宽度也没有跟随变动. ...
- vue async/await同步 案例
1.async/await场景 这是一个用同步的思维来解决异步问题的方案,当前端接口调用需要等到接口返回值以后渲染页面时. 2.名词解释 >async async的用法,它作为一个关键字放到函数 ...
- Spring实战 MethodInvokingJobDetailFactoryBean使用与分析
定义一个Job类 public class OffsetsQuartz { public void jobQuartz() { String[] clusterAliass = SystemConfi ...
- linux下如何实现mysql数据库每天自动备份定时备份
版权声明:本文为 testcs_dn(微wx笑) 原创文章,非商用自由转载-保持署名-注明出处,谢谢. 目录(?)[+] 概述 备份是容灾的基础,是指为防止系统出现操作失误或系统故障导致数 ...