RPC:远程过程调用

主要内容

1.项目结构变化

2.RPC简介

3.RMI实现RPC

4.HttpClient实现RPC

5.Zookeeper安装

6.Zookeeper客户端常用命令

7.向Zookeeper中注册内容

8.从Zookeeper中发现内容

9.手写RPC框架

一.今天学什么?为什么讲?

Dubbo是RPC的一个框架.

二.项目架构变化

1.单体架构

1.1架构图

单体架构就是一个项目里面包含这个项目中全部代码.一个应用搞定全部功能.

DNS服务器可以是单映射,也可以配置多个映射.

1.2软阿基代码结构

在单体架构项目中,团队都是通过包(package)进行区分每个模块

总体包结构:com.bjsxt.*.分层包

项目名:

--com

--bjsxt

--common

--utils

--user

--controller

--service

--mapper

--sys

--controller

--service

--mapper

1.3优缺点

1.3.1优点

部署简单,维护方便,开发成本低

1.3.2缺点

当项目规模大,用户访问频率高,并发量大,数据量大时,会大大降低程序执行效率,甚至出现服务器宕机等情况

1.4适用项目

传统管理项目,小型互联网项目

2.分布式架构

2.1架构图(简易版)

分布式架构会把一个项目按照特定要求(多按照模块或功能)拆分成多个项目,每个项目分别部署到不同的服务器上.

2.2软件代码结构

项目1:

--com.bjsxt.xxx

--controller

--service

--mapper

项目2:

--com.bjsxt.mmm

--controller

--service

--mapper

2.3优缺点

2.3.1优点

增大了系统可用性.减少单点故障,导致整个应用不可用

增加重用性.因为模块化,所以重用性更高.高内聚,低耦合

增加可扩展性.有新的模块增加新的项目即可

增加每个模块的负载能力.因为每个模块都是一个项目,所以每个模块的负载能力更强

2.3.2缺点

成本更高.因为技术多,难,所以开大成本,时间成本,维护成本都在变高

架构更加复杂

整体响应之间变长,一些业务需要多项目通信后给出结果

通吐量更大.吞吐量=请求数/秒

2.4适用项目

中,大型互联网项目.客户多,数据多,访问并发高,压力大,吞吐量高

2.5待解决问题

分布式架构中各个模块如何进行通信?

可以使用Http协议,也可以石红RPC协议通信,也可以使用其他的通信方式.我们本阶段使用的是RPC协议,因为它比HTTP更适合项目内部通信

三.RPC简介

1.RFC

RFC(Request For Comments)是由互联网工程任务组(IEIF)发布的文件集.文件集中每个文件都有自己唯一编号.例如:rfc1831.目前RFC文件由互联网协会(Internet Society,ISOC)赞助发行

RPC就收集在RFC1831中.可以通过下面网址查看:

2.RPC

RPC在rgc1831中收录,RPC(Remote Procedure Call)远程过程调用协议

RPC协议规定允许互联网中一台主机程序调动另一台主机程序,而程序员无需对这个交互过程进行编程.在RPC协议中强调当A程序调用B程序中功能或方法时,A是不知道B中方法具体实现的

RPC是上层协议,底层可以基于TCP协议,也可以基于HTTP协议.一般我们说RPC都是基于RPC的具体实现,如:Dubbo框架.从广义上讲只要是满足网络中进行通信调用都统称为RPC,甚至HTTP协议都可以说是RPC的具体实现,但是具体分析看来RPC协议要比HTTP协议更加高效,基于RPC的框架功能更多

RPC协议是基于分布式架构而出现的,所以RPC在分布式项目中有着得天独厚的优势

3.RPC和HTTP对比

3.1具体实现

RPC:可以基于TCP协议,也可以基于HTTP协议

HTTP:基于HTTP协议

3.2效率

RPC:自定义具体实现可以减少很多无用的报文内容,使得报文体积更小

HTTP:如果是HTTP1.1报文中很多内容都是无用的.如果是HTTP2.0以后和RPC相差不大,比RPC少的可能就是一些服务治理等功能

3.3连接方式

RPC:长链接支持

HTTP:每次连接都是3次握手(断开连接为4次挥手)

3.4性能

RPC可以基于很多序列化方式.如:thrift

HTTP主要是通过JSON,序列化和方序列化效率更低

3.5注册中心

RPC:一般RPC框架都带有注册中心

HTTP:都是直连

3.6负载均衡

RPC:绝大多数RPC框架都带有负载均衡测量

HTTP:一般都需要借助第三方工具.如:nginx

3.7综合结论

RPC框架一般都带有丰富的服务治理等功能,更适合企业内部接口调用.而HTTP更适合多平台之间相互调用

四.HttpClient实现RPC

1.HttpClient简介

在JDK中java.net包下提供了用户HTTP访问的基本功能,但是它缺少灵活性或许多应用所需要的功能

HttpClient起初是Apache Jackarta Common的子项目.用来提供高效的,最新的,功能丰富的支持HTTP协议的客户端编程工具包,并且他支持HTTP协议最新的版本.2007年成为顶级项目

通俗解释:HttpClient可以实现Java代码完成标准HTTP请求及响应

2.代码实现

2.1服务端

新建项目HttpClientServer

2.1.1新建控制器

com.bjsxt.controller.DemoController

@Controller

public class DemoController{

@RequestMapping("/demo")

@ResponseBody

public String demo(String param){

return "demo"+param;

}

}

2.1.2新建启动器

com.bjsxt.HttpClientServerApplication

@SpringBootApplication

public class HttpClientServerApplication{

public static void main(String[] args){

SpringApplication.run(HttpClientServerApplication.class,args);

}

}

2.2客户端

新建HttpClientDemo项目

2.2.1添加依赖

org.apache.httpcomponents

httpclient

4.5.10

2.2.2新建类

新建com.bsjxt.HttpClientDemo,编写主方法

2.2.2.1使用POST方法访问

public class HttpClientDemo{

public static void main(String[] args){

try{

CloseableHttpClient httpClient = HttpClients.createDefault();

HttpPost post = new HttpPost("http://localhost:8080/demo");

HttpEntity httpEntity = null;

Listparams = new ArrayList<>();

params.add(new BasicNameValuePair("param","123"));

StringEntity entity = new UrlEncodedFormEntity(params,"utf-8");

post.setEntity(entity);

CloseableHttpResponse response = httpClient.execute(post);

String result = EntityUtils.toString(response.getEntity());

System.out.println(result);

response.close();

httpClient.close();

}catcha(IOException e){

e.printStackTrace();

}

}

}

2.2.2.2使用GET方式访问

public static void main(String[] args){

try{

CloseableHttpClient httpClient = HttpClients.createDefault();

URIBuilder uriBuilder = new URIBuilder("http://localhost:8080/demo");

uriBuilder.addParameter("param","get123");

HttpGet get = new HttpGet(uriBuilder.build());

CloseableHttpResponse response = httpClient.execute(get);

String result = EntityUtils.toString(response.getEntity(),"utf-8");

System.out.println(result);

response.close();

httpClient.close();

}catch(URISyntaxException e){

e.printStackTrace();

}catch(IOException e){

e.printlnStackTrace();

}

}

3.HttpClient请求包含JSON

3.1java代理实现

public class HttpClientDemo{

public static void main(Stirng[] args){

try{

CloseableHttpClient httpClient = HttpClients.createDefault();

HttpPost post = new HttpPost("http://localhost:8080/demo");

HttpEntity httpEntity = null;

String json = "{}";

StringEntity entity = new StringEntity(json,ContentType.APPLICATION_JSON);

post.setEntity(entity);

CloseableHttpResponse response = httpClient.execute(post);

String result - EntityUtils.toString(response.getEntity());

System.out.println(result);

response.close();

httpClient.close();

}catch(IOException e){

e.printStackTrace();

}

}

}

4.服务端控制器接口参数

@RequestBody把请求体中六数据转换为指定的对象.多用在请求体参数是json数据且请求的Content-Type="application/json"

@RequestMapping("/demo4")

@ResponseBody

public String demo4(@RequestBody Listlist){

System.out.println(list);

return list.toString();

}

5.Jackson用法

5.1把对象转换为json字符串

ObjectMapper objectMapper = new ObjectMapper();

People peo = new People();

String jsonStr = objectMapper.writeValueAsString(peo);

5.2把json字符串转换为对象

ObjectMapper objectMapper= new ObjectMapper();

People peo = objectMapper.readValue(jsonStr,People.class);

5.3把json字符串转换为List集合

ObjectMapper objectMapper = new ObjectMapper();

JavaType javaType = objectMapper.getTypeFactory().constructParametericType(List.class,People.class);

List list = objectMapper.readValue(jsonStr,javaType);

6.Ajax发送json参数写法

var json = '[{"id":123,"name":"bjsxt"},{"id":123,"name:"bjsxt"}]';

$.ajax({

url:'/demo5',

success:function(data}{

alert(data);

for(var i=0; i

alert(data[i].id+"  "+data[i].name);

}

},

contentType:'application/json',//请求体中参数类型

dataType:'json',//响应内容类型

data:json

});

7.跨域

跨域:协议,端口,ip中只要有一个不同就是跨域请求

同源策略:浏览器默认只允许ajax访问同源(协议,ip,端口都相同)内容

解决同源策略:

在控制器接口上天啊及@CrossOrigin.表示允许跨域.本质在响应头中添加

Access-Control-Allow-Origin:*

@RequestMapping("/demo5")

@ResponseBody

@CrossOrigin

public Listdemo5(@RequestBody Listlist){

System.put.println(list);

return list;

}

五.RMI实现RPC

1.RMI简介

RMI(Remote Method Invocation)远程方法调用

RMI是从JDK1.2推出的功能,它可以实现在一个java应用中可以像调用本地方法一样调用另一个服务器中java应用(JVM)中的内容

RMI是java语言的远程调用,无法实现跨语言

2.执行流程

Registry(注册表)是防止所有服务器对象的命名空间.每次服务端创建一个对象时,它都会使用bind()或rebind()方法注册该对象.这些是使用称为名称的唯一名称注册的.

要调用远程对象,客户端需要该对象的引用.即通过服务端绑定的名称从注册表中获取对象(lookup()方法)

3.API介绍

3.1Remote

java.rmi.Remote定义了此接口为远程调用接口.如果接口被外部调用,需要继承次接口

3.2RemoteException

java.rmi.RemoteException

继承了Remote接口,如果方法是允许被远程调用的,需要抛出此异常

3.3UnicastRemoteObject

java.rmi.server.UnicastRemoteObject

此类实现了Remote接口和Serializable接口

自定义接口实现类除了实现自定义接口还需要继承此类

3.4LocateRegistry

java.rmi.registry.LocateRegistry

可以通过LocateRegistry子本机上创建Registry,通过特定的端口就可以访问这个Registry

3.5Naming

java.rmi.Naming

Naming定义了发布内容可访问RMI名称.也是通过Naming获取到指定的远程方法

4.代码实现

4.1服务端创建

创建RmiServer项目

4.1.1编写接口

com.bjsxt.service.DemoService编写

public interface DemoService extends Remote{

String demo(String demo)throws RemoteException;

}

4.1.2.编写实现类

com.bsjxt.service.impl.DemoServiceImpl编写

注意:

构造方法是public的.默认生成protected

public class DemoServiceImpl extends UnicastRemoteObject implements DemoService{

public DemoServiceImpl() throws RemoteException{}

@Override

public String demo(String demo)throws RemoteException{

return demo+"123";

}

}

4.1.3编写主方法

编写com.bjsxt.DemoService类,生成主方法

public class DemoServer{

public static void main(String[] args){

try{

DemoService demoService = new DemoServiceImpl();

LocateRegistry.createRegistry(8888);

Naming.bind("rmi://localhsot:8888/demoService",demoService);

}catch(RemoteException e){

e.printStackTrace();

}catch(AlreadyBoundException e){

e.printStackTrace();

}catch(malformedURLException){

e.printStackTrace();

}

}

}

4.1.4运行项目

运行项目后,项目一直处于启动状态,表示可以远程访问此项目中的远程方法

4.2创建客户端代码

创建项目RmiClient

4.2.1复制服务端接口

把服务端com.bjsxt.service.DemoService粘贴到项目中

注意:复制代码仅为快速完成案例,学习技术,在商业开发中,DemoService接口应该使用独立的工程定义,并在服务端和客户端工程中通过依赖的方式引入

4.2.2创建主方法类

新建com.bjsxt.DemoClient

public class DemoClient{

public static void main(String[] args){

try{

DemoService demoService = (DemoService)Naming.lookup("rmi://localhost:8888/demoService");

String result = demoService.demo("demo34");

System.out.println(result);

}catch(NotBoundException e){

e.printStackTrace();

}catch(MalformedURLException e){

e.printStackTrace();

}catch(RemoteException e){

e.printStackTrace();

}

}

}

六.Zookeeper安装

七.常用命令

八.向Zookeeper中注册内容

先进项目ZookeeperClient

1.创建/demo节点

使用zookeeper的客户端命令工具创建/demo

./zkCli.sh

create /demo

2.添加依赖

org.apache.zookeeper

zookeeper

3.5.5

3.编写代码

创建类com.bjsxt.MyApp

ZooDefs.Ids.OPEN-ACL_UNSAFE表示权限

CreateMode.PERSISTENT_SEQUENTIAL永久存储,文件内容编写递增

public static void main(String[] args){

try{

Zookeeper zookeeper = new Zookeeper("192.168.232.132:2181",60000,new Watcher(){;

@Override

public void process(WatcherEvent watchedEvent){

System.out.println("获取连接");

}

});

String content = zookeeper.create("/demo/nn","content".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);

System.out.println("content"+content);

}catch(IOException e){

e.printStackTrace();

}catch(KeeperException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

4.查看上传数据

ls -R /    查看列表

get /demo/nn000000002     查看内容

九.从zookeeper中发现内容

在原有项目中新建一个类,类中编写主方法

public static void main(String[] args){

try{

Zookeeper zookeeper = new Zookeeper("192.168.232.132:2181",60000,new Watcher(){

@Override

public void process(WatchedEvent watchedEvent){

System.out.println("获取连接");

}

});

//获取列表

Listlist = zookeeper.getChildren("/demo",false);

for(String child:list){

byte[] result = zookeeper.getData("/demo/"+child,false,null);

Ssytem.out.println(new String(result));

}

}catch(IOException e){

e.printStackTrace();

}catch(KeeperException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

十.手写RPC框架

使用Zookeeper作为注册中心,RMI作为连接技术,手写RPC框架

1.创建父项目ParentDemo

包含3个集合子项目

service:包含被serviceImpl和consumer依赖的接口

serviceImpl:provider提供的服务内容

consumer:消费者,调用服务内容

2.在父项目中添加依赖

org.springframework.boot

spring-boot-starter-parent

2.1.10.RELEASE

org.springframework.boot

spring-boot-starter-web

org.apache.zookeeper

zookeeper

3.5.5

3.创建service项目

项目结构如下:此项目中重点编写需要被两个项目依赖的接口

4.创建DemoService接口

创建com.bjsxt.DemoService,具体内容如下

public interface DemoService extends Remote{

String demo(String param)throws RemoteException;

}

5.创建serviceImpl项目

此项目编写接口具体实现,RMI服务发布和把信息发送到Zookeeper中

项目结构如下:

在pom.xml中添加对service项目的依赖

service

com.bjsxt

1.0-SNAPSHOT

6.创建DemoServiceImpl

创建com.bjsxt.service.impl.DemoServiceImpl

public class DemoServiceImpl extends UnicastRemoteObject implements DemoService{

public DemoServiceImpl()throws RemoteException{

}

@Override

public String demo(String param)throws RemoteException{

return param+"123";

}

}

7.创建RmiRun

创建com.bsjxt.RmiRun.实现RMI服务的发布和Zookeeper消息的发布

public class RmiRun{

public static void main(String[] args){

try{

DemoService demoService = new DemoServiceImpl();

LocateRegistry.createRegistry(8888);

String url = "rmi://localhsot:8888/demoService";

Naming.bind(url,demoService);

Zookeeper zookeeper = new Zookeeper("192.168.232.132:2181",60000,new Watcher(){

@Override

public void process(WatcherEvent watchedEvent){

Ssytem.out.println("获取连接");

}

});

String content = zookeeper.create("/demo/demoService",url.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);

System.out.println("服务发布成功...");

}catch(AlreadyBoundException e){

e.printStackTrace();

}catch(IOException e){

e.printStackTrace();

}catch(KeeperException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}

8.创建Consumer项目

新建consumer项目,此项目需要从zookeeper中获取rmi信息,并调用rmi服务

在pom.xml中添加对service项目的依赖

service

com.bjsxt

1.0-SNAPSHOT

9.创建接口和实现类

创建com.bjsxt.service.ConsumerService接口

创建com.bjsxt.servioce.impl.ConsumerServiceImpl实现类

public interface ConsumerService{

String consumerService(String param);

}

@Service

public class ConsumerServiceImpl implements ConsumerService{

@Override

public String consumerService(String param){

try{

Zookeeper zookeeper = new Zookeeper("192.168.232.132:2181",60000,new Watcher(){

@Override

public void process(WatchedEvent watchedEvent){

System.out.println("获取连接");

}

});

byte[] urlByte = zookeeper.getData("/demo/demoService",false,null);

DemoService demoService = (DemoService)Naming.lookup(new String(urlByte));

String result = demoService.demo(param);

System.out.println(result);

return result;

}catch(IOException e){

e.printStackTrace();

}catch(InteruptedException e){

e.printlnStackTrace();

}catch(NotBoundException e){

e.printStackTrace();

}

return null;

}

}

10.创建控制器

创建com.bjsxt.controller.DemoController控制器

@Controller

public class DemoController{

@Autowired

private ConsumerService consumerService;

@RequestMapping("/demo")

@ResponseBody

public String demo(String param){

return consumerService.consumerService(param);

}

}

11.创建启动器

创建com.bjsxt.ConsumerApplication

@SpringBootApplication

public class ConsumerApplication{

public static void main(String[] args){

SpringApplication.run(ConsumerApplication.class,args);

}

}

12.测试

在浏览器输入:http://localhost:8080/demo?param=demo

观察结果是否是:demo123

zkcli远程连接_高级框架第一天RPC:远程过程调用相关推荐

  1. 远程连接linux的mysql_【Linux开启mysql远程连接的设置步骤】 mysql开启远程连接

    相关热词搜索:Linux开启mysql远程连接的设置步骤,linux mysql 远程连接,linux连接mysql数据库, MySQL默认root用户只能本地访问,不能远程连接管理mysql数据库, ...

  2. 远程连接Kali Linux使用PuTTY实现SSH远程连接

    远程连接Kali Linux使用PuTTY实现SSH远程连接 本书主要以在Android设备上安装的Kali Linux操作系统为主,介绍基于Bash Shell渗透测试.由于在默认情况下,在Andr ...

  3. 软件实施工程师远程连接_新研究生远程软件工程师的大流行生存指南。

    软件实施工程师远程连接 In May 2020, I started my first job out of university as a software engineer at Facebook ...

  4. mysql数据库开启远程连接_安装MySQL数据库并开启远程访问

    一.安装MySQL数据库 MySQL安装在系统盘下(C:\Program Files),方便系统备份. 1.双击安装程序,勾选"I accept the license terms" ...

  5. centos6安装mysql并远程连接_阿里云服务器上安装redis并实现远程连接

    一.概述 之前一直将redis安装在本地,为了在服务器上使用redis进行数据的存储,需要在服务器端进行redis的安装,本次使用的是阿里云服务器,由于是第一安装,在安装及后续远程连接过程中也遇到一些 ...

  6. hp 交换机远程连接_光收发器怎么安装,光纤收发器连接示意图解

    对于光纤布线来讲光纤收发器都是非常熟悉的产品了,在光纤网络中,我们常常会使用到光纤收发器,那么,在网络布线过程中光纤收发器该怎么连接呢?接下来飞畅科技的小编就来为大家介绍下光纤收发器安装以及连接图解, ...

  7. centos6安装mysql并远程连接_如何开启phpstudy中mysql的远程连接

    phpstudy是一款非常方便的php集成环境,许多人会使用它作为PHP网站的实验环境.phpstudy中也集成了Mysql数据库,那么集成环境中的mysql数据库如何才能远程连接呢? 通常情况下,实 ...

  8. mysql server远程连接_本地远程连接 MySQL server

    问题 MySql Server 出于安全方面考虑默认只允许本机(localhost, 127.0.0.1)来连接访问.如果想远程访问,需要额外做下操作. 配置修改 定位文件 /etc/mysql/my ...

  9. pg数据库开启远程连接_疫情之下,开启在家办公模式,远程连接工具篇之向日葵...

    1月30号本来就要返程去上班了,接到公司通知,根据当前疫情的形势,假期延长到3号,退车票,候补抢票一顿操作,将票改到了3号,3号又接到通知假期延长到10号.作为一个一线的销售人员,工作肯定不能丢,就只 ...

最新文章

  1. 好渴望 wacom Intuos3
  2. STM32串口+DMA使用1
  3. 用MVC做可拖拽的留言板,利用 Jquery模板 -- JsRender
  4. TCP/IP review之 静态路由
  5. Android短信页面
  6. Python--turtle.circle()参数说明
  7. linux之tcpdump抓包工具
  8. 软件工程--快速原型模型详解
  9. 沈阳移动打造“爱贝通”、“校讯通”业务助少年儿童健康成长
  10. 将一个3x4阶矩阵转置。
  11. Java线程池与Lambda表达式
  12. C#:查找文件所在位置
  13. 【对抗攻击论文笔记】Enhancing the Transferability of Adversarial Attacks through Variance Tuning
  14. 微星GT77HX-13VI2023原厂Windows11重建F3一键恢复msirestore功能
  15. mac SnailSVN如何拉取多个svn副本
  16. 近期iOS开发者问题全面答疑(3)
  17. 首届“十大最具价值”智能安防创业项目遴选榜单丨Xtecher联合中投协权威发布...
  18. tomcat资源请求慢_tomcat响应过慢——解决办法
  19. 国外电商网站snapdeal爬取流程
  20. VLAN配置(IN8000系列交换机)

热门文章

  1. Centos 6.5 linux 安装nginx
  2. 【转】想象5年后的你
  3. 学习笔记(1):uni-app实战社区交友类app开发-引入自定义图标库
  4. Tensorflow 入门手册(代码与原理释义)
  5. ajax连接前后端原理,前后端数据交互方法和原理
  6. linux 随机10字符病毒,Linux系统随机10字符病毒的清除
  7. 比机器人更优越的半机械昆虫,颜控党们会接受吗?
  8. futureTask的超时原理解析
  9. 资金流学习 - 选股逻辑
  10. Android动画类型