首页 » 网站推广 » phprestfulapi例子技巧_优秀API的设计原则与实例实现RESTful

phprestfulapi例子技巧_优秀API的设计原则与实例实现RESTful

duote123 2024-11-09 0

扫一扫用手机浏览

文章目录 [+]

API是做事之间通信的左券,通过API可以忽略做事内部实现的细节。
如果接口设计良好,则可以降落团队间的耦合度,加快开拓速率。

精良API的设计原则

设计出精良的API常日须要遵照如下原则。

phprestfulapi例子技巧_优秀API的设计原则与实例实现RESTful

· 大略:API该当符合大多数人正常的思维逻辑,避免异想天开的交互,知足需求的同时,越大略越好。

phprestfulapi例子技巧_优秀API的设计原则与实例实现RESTful
(图片来自网络侵删)

· 易懂:精良的API可读性好,只管即便做到不须要文档就能读懂接口名称、参数的大概含义,供应给第三方开拓者的接口要进行详细地描述,包括参数的取值范围、缺点码、非常返回规则、SLA干系指标等。

· 同等:对付同一个公司、站点供应的API,最好有统一的规则,让开发者只要看过几个API之后,基本都能猜到剩余API的含义。

· 稳定:最好在开始的时候就考虑好,不要轻易修正API,否则会给利用者造成非常大的麻烦。
如果修正API无法避免,那么最好通过增加接口而不是修正已有接口做到兼容。
如果一定要改变已有接口,也要通过明确的版本号加以区分,并且预留足够的韶光。

· 安全:设计时要考虑超出预期的情形如何处理,给出被限流的情形。
下面是GitHub API利用的两个干系的头部参数。

¡ X-RateLimit-Limit:每小时许可发送要求的最大值。

¡ X-RateLimit-Remaining:当前韶光窗口剩下的可用要求数目。

如果供应给第三方,则要考虑如何认证,租户之间如何隔离,并且只管即便利用HTTPS协议。
如果验证失落败,则要返回401 Unauthorized状态码;如果没有被授权访问,则要返回403 Forbidden状态码,并且供应详细的缺点信息。

做事间通信——RPC

RPC(Remote Procedure Call)是指远程过程调用。
大略来说,RPC希望达到的效果是,调用远程方法就像调用本地方法一样。
由于调用方和被调用方实际上分布在不同的机器上,一样平常情形下,会有一个框架来支撑,以便屏蔽底层通信细节,让双方开拓起来更大略。

一个普通的RPC调用流程如图2-11所示,详细调用过程如下。

(1)客户端在业务做事中发起要求。

(2)调用本地stub,本地stub对进行序列化、封装等处理。

(3)客户端stub调用网络通信模块将投递做事端,中间还可能包括寻址、建连接等一系列操作。

(4)做事端网络通信模块把吸收到的转发给stub进行反序列化。

(5)stub转发给业务做事进行处理并返回结果。

(6)stub将结果进行序列化,调用网络通信模块。

(7)做事端通过网络通信模块将结果返回到客户端网络通信模块中。

(8)客户端网络通信模块将转发给stub。

(9)stub进行反序列化并转发给客户端业务做事。

(10)客户端得到终极结果。

我们的目标是让(2)到(9)对开拓者不可见。

既然哀求像调用本地方法一样调用远程方法,那就不但是要屏蔽繁芜度,还要在性能上进行考虑。

影响RPC性能的成分如下。

· 序列化。
常用的RPC序列化协议包括:Thrift、Protobuf、Avro、Kryo、MsgPack 、Hessian、Jackson。

图2-11 RPC调用流程图

· 传输协议。
常用的传输协包括:HTTP、Socket、TCP、UDP等。

· 连接。
连接包括:长连接、短连接。

· IO模型。
常用的网络IO模型:同步壅塞IO(Blocking IO)、同步非壅塞IO(Non-blocking IO)、IO多路复用(IO Multiplexing)、异步IO(Asynchronous IO)。

序列化——Protobuf

Protobuf是由Google开源的传输协议,用于将构造化的数据序列化、反序列化通过网络进行传输,目前被广泛运用的紧张版本有Protobuf 2和Protobuf 3。
Protobuf首先办理的是如何在不同措辞之间通报数据的问题,目前支持的编程措辞有Java、C++、Python、Ruby、PHP、Go等。
通过Protobuf可以很随意马虎地实现一个Client和一个Server之间的数据通报,Client和Server可以利用不同措辞。

Protobuf是一个高性能、易扩展的序列化框架,常日是RPC调用追求高性能的首选。
它本身非常大略,易于开拓,结合Netty可以非常便捷地实现RPC调用。
同时,可以利用Netty为Protobuf办理有关Socket通信中“半包、粘包”等问题(反序列化时,字节成帧)。

Protobuf比JSON、XML等更快、更轻、更小,并且可以跨平台。
Protobuf最新的版本为3.x,如果利用它,首先要编写proto文件,即IDL文件(后缀为“.proto”的文本文件),然后通过客户端天生Java干系类进行序列化、反序列化。

下面我们就大略描述一下基于Protobuf实现序列化、反序列化的步骤。

1.安装客户端

通过brew可以实现在Mac下安装Protobuf,实行命令如下。

brew install protobuf

如果涌现如下实行结果,意味着已经安装成功了。

/usr/local/Cellar/protobuf/3.5.1: 267 files, 18.0MB

也可以通过如下命令考验是否安装成功。

protoc –version

2.安装工具

为了在编辑proto文件的时候得到更好的体验,可以先安装插件。
idea里可以安装Protobuf Support,在插件库中搜索后直接安装即可,如图2-12所示。

图2-12 idea安装Protobuf Support插件

Protobuf Support可以对语法高亮显示、缺点提示,如图2-13所示。

图2-13 Protobuf Support插件效果

3.编辑proto文件

本节采取的Protobuf 3.x,须要遵照proto 3的语法。
关于Protobuf的数据类型和Java的数据类型如何对应,可以参照表2-3供应的对应关系。

定义product.proto文件的过程如下。

syntax = "proto3";//声明支持的版本是proto 3 option java_package = "com.cloudnative.protobuf";//声明包名,可选option java_outer_classname="ProductProtos";//声明类名,可选 message Product { int32 id = 1; string name = 2; string price = 3; enum ColorType {//定义列举类型 WHITE = 0; RED = 1; BLACK = 2; }}

在命令行实行如下代码。

protoc --java_out=../java product.proto

--java_out表示在目标目录中天生Java代码。
由于已将product.proto放到src/mian/java/proto目录下,以是--java_out=../java参数会将天生的Java类创建到java目录下,如图2-14所示。

图2-14 项目目录构造

打开ProtobufProtos会创造,这是一个非常繁芜的类,其代码大概1500行。

4.利用Protobuf序列化

引入Protobuf-java包,可以先通过http://mvnrepository.com查询,然后点击复制,非常方便,如图2-15所示。

图2-15 查询结果

实际上,Protobuf的序列化及反序列化非常大略。
Protobuf天生的类中已经实现了相应的方法,调用即可。
示例代码如下。

package com.cloudnative.protobuf; import com.google.protobuf.InvalidProtocolBufferException; public class TestProtobuf { public static void main(String[] args){ TestProtobuf testProtobuf =new TestProtobuf(); byte[] buf=testProtobuf.toByte(); try { ProductProtos.Product product = testProtobuf.toProduct(buf); System.out.println(product); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } } //序列化 private byte[] toByte(){ ProductProtos.Product.Builder productBuilder=ProductProtos.Product.newBuilder(); productBuilder.setId(11); productBuilder.setName("milk"); productBuilder.setPrice("4.12"); ProductProtos.Product product =productBuilder.build(); byte[] buf = product.toByteArray(); System.out.println(buf.length); return buf; } //反序列化 private ProductProtos.Product toProduct(byte[] buf) throws InvalidProtocolBufferException { return ProductProtos.Product.parseFrom(buf);}}做事间通信——RESTful

REST是Roy Thomas Fielding在2000年的博士论文中提出的。
REST是Representational State Transfer的缩写,常日翻译为“表现层状态转化”。
如果一个架构符合REST原则,就称它为RESTful架构。

API如何设计才能知足RESTful的哀求呢?

1.协议

API是基于HTTP的协议。

2.域名

API要有一个域名,例如http://api.xxx.com

3.版本

API要有版本信息。
当客户端数量较多或者供应给第三方利用时,很难掌握客户真个兼容性,一个比较好的做法便是当已发布的做事变更时,通过版本来掌握兼容性。
当然,版本不能演进太快,最好的版本化便是无须版本,例如http://api.xxx.com/v1/

4.路径

要理解REST,首先要理解什么是资源(Resource)。
REST开拓又被称作面向资源的开拓。
API要用资源来表示,URL中不能涌现动词。
资源是做事端可命名的一个抽象的观点,只要客户端随意马虎理解,可以随意抽象。
常日可以把资源算作是一个实体,例如用户、邮件、图片等,用URI(统一资源定位符)指向它。
履历见告我们,每每这里的资源和数据库的表名是对应关系。
一种不雅观点认为DDD可以和REST API很好地契合,由于REST的资源可以很好地与DDD的实体映射起来。
定义资源的时候,推举用复数,假设我们要获取用户的信息,大概是这样:http://api.xxx.com/v1/users/

5.方法

一样平常许可的方法紧张包括如下几种。

· GET:读取资源,一个或多个(常用)。
· POST:创建资源(常用)。
· PUT:修正资源,客户端供应修正后的完全资源(常用)。
· PATCH:对已知资源进行局部更新,客户端只须要供应改变的属性。
· DELETE:删除、回收资源(常用)。
· HEAD:读取资源的元数据(不常用)。
· OPTIONS:读取对资源的访问权限(不常用)。

一样平常情形下,GET、POST、PUT、DELETE已经足够,乃至有一种不雅观点认为,只须要利用GET、POST即可,例子如下所示。

· GET/users/1,获取用户ID为1的用户信息。

· GET/users/1/orders,获取用户ID为1的用户拥有的所有订单。

6.参数

参数可以放到API路径中,也可以放到“?”的后面。

GET/users/1/ordersGET/orders?user_id=1

7.编码

虽然RESTful并没有限定资源的表达格式,HTML/XML/JSON/纯文本/图片/视频/音频等都可以,但是常日做事端和客户端通过JSON通报信息。

8.状态码

用HTTP Status Code通报Server的状态信息,常用的状态码如下。

· 100Continue· 200OK,GET· 201Created,POST/PUT/PATCH· 202Accepted· 204NO Content,DELETE· 400Bad Request,POST/PUT/PATCH· 401Unauthorized· 403Forbidden· 404Not Found· 405Method Not Allowed· 406Not Acceptable· 409Conflict· 410Gone· 412Precondition Failed· 429Too many requests· 500Internal Server Error· 501Not Implemented· 503Service Unavailable

完全信息可以参考w3官网。

要理解RESTful,还要考虑如下主要的约束条件。
当然,这些条件也不是绝对的,须要结合业务场景来确定。

· 单一职责。
只管即便保持接口职责单一,留给客户端足够的操作空间,以知足不同的业务需求。
对付接口粒度的大小,须要考虑的成分包括:性能(合并要求性能更高)、同等性、灵巧性及客户真个易用程度。

· 幂等性。
一次和多次要求某一个资源该当具有同样的浸染,客户端能够重复发起要求而不必担心造成副浸染。

· 无状态。
多次要求之间不应该存在状态耦合,无须关联过去、现在和将来的要求或者相应。

· 客户端发起。
一样平常通信办法都是由客户端发起的,做事端是被调用的。
随着HTTP/2的到来,这一条可能会发生变革。

· 原子性。
担保所有操作是一个不可分割的单元,要么全部成功,要么全部失落败,须要结合业务哀求加以确定。

· 易用。
须要供应详尽的文档、参数解释、示例等,API定义的URL、变量名要普通易懂,最好是英文,只管即便减少自定义的缩写,让开发者随意马虎调试和管理。

· SLA。
须要供应相应韶光、吞吐量、可用性等关键指标。

RESTful已经成为业界的主流,紧张是由于RESTful常日采取HTTP+JSON的办法实现,继续了HTTP和JSON的优点。
相对付SOAP、RPC等办法,RESTful更加轻量、大略,支持跨措辞,并且随意马虎调试。

通过Swagger实现RESTful

传统的API设计常日先完成代码,然后其余补充一份解释文档,这种办法效率比较低,文档和代码缺少关联性。
更高等一点的做法是利用JAVADOC,把文档和注释关联起来,以提升效率,但是由于JAVADOC须要不断天生,文档难免和代码存在不一致。

在此背景下,Swagger出身了。
Swagger是一个大略、功能强大、非常盛行的API表达工具。
基于Swagger天生API,可以得到交互式文档、自动天生代码的SDK,以及API的创造办法等。
通过Swagger可以很随意马虎地天生标准的API,示例如图2-16所示。

图2-16 基于Swagger天生API的示例

Swagger是基于OpenAPI的,OpenAPI支持YAML和JSON格式描述API。
YAML相对付JSON来说更加简洁,比较适宜做简洁的序列化和配置文件。
编写YAML文档推举利用Swagger Editor,它供应了语法高亮、自动完成、即时预览等功能。
编辑器可以在本地利用,也可以在线利用。
YAML的数据构造可以用类似大纲的缩排办法呈现,构造通过缩进来表示,连续的项目通过“-”来表示,map构造里面的key/value对用“:”来分隔。

基于Swagger Editor设计API,可以直接在线编辑API,也可以在本地安装,下面以在线编辑器为例先容如何基于Swagger构建API。

(1)访问官方Editor编辑器

http://editor2.swagger.io。

(2)编辑YAML文件,如下所示。

swagger: "2.0" info: version: 1.0.0 title: Product API description: Product API for test schemes: - httpshost: localhostbasePath: /product paths: {}

下面大略解释一下这个文档。
首先,显示OpenAPI利用的版本是2.0。

swagger: "2.0"

API的描述信息,包括如API文档版本(version)、API文档名称(title)和描述信息(description)。

info: version: 1.0.0 title: Product API description: Product API for test

下面的代码表示API的URL,采取HTTPS协议,先容了主机名(host)、根路径(basePath)。

schemes: - httpshost: localhostbasePath: /product

下面我们来看一个稍繁芜一点的示例。

swagger: '2.0'info: version: '1.0' title: Swagger构建RESTful APIhost: 'localhost:8080'basePath: /tags: - name: product-controller description: Product Controllerpaths: /products: get: tags: - product-controller summary: 获取产品列表 description: 获取产品列表 operationId: getProductListUsingGET consumes: - application/json produces: - '/' responses: '200': description: OK schema: type: array items: $ref: '#/definitions/Product' '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found /products/{id}: get: tags: - product-controller summary: 获取产品详细信息 description: 根据URL的id来获取产品详细信息 operationId: getProductUsingGET consumes: - application/json produces: - '/' parameters: - name: id in: path description: 产品ID required: true type: integer responses: '200': description: OK schema: $ref: '#/definitions/Product' '401': description: Unauthorized '403': description: Forbidden '404': description: Not Founddefinitions: Product: type: object properties: count: type: integer format: int32 desc: type: string id: type: integer format: int32 name: type: string

上面的示例定义了两个API,一个是获取Product的列表,一个是根据id获取Product的详情。

编辑完成后,可以得到如图2-17所示的文档界面。

图2-17 Swagger天生文档的示例

(3)点击file-download yaml下载YAML文件。

(4)点击generate server下载做事端,点击generate client下载客户端,可以分别天生相应措辞的SDK工程。

通过Spring Boot、Springfox、Swagger实现RESTful

上一节先容了通过Swagger Editor实现API设计(先写YAML文件,然后天生做事端和客户端),本节先容其余一种直接写代码、通过表明自动天生干系文档的方法。

Spring Boot已经家喻户晓,而Springfox是什么呢?Marty Pitt曾经编写了一个基于Spring的组件swagger-springmvc,用于将Swagger集成到Spring MVC中,Springfox是从这个组件发展而来的。

下面我们通过一个大略的示例来解释一下。
首先,新建一个项目,基于Maven构建,在pom中引入相应的JAR包,这里须要引入Spring Boot和Springfox的干系包。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version></dependency>

编写Swagger的配置类。

@Configuration@EnableSwagger2public class Swagger2 { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.cloudnative.rest")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger构建RESTful API") .description("") .termsOfServiceUrl("") .version("1.0") .build(); } }

实现dto类。

public class Product { private int id; private String name; private int count; private String desc; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "Product{" + "id=" + id + ", name='" + name + '\'' + ", count=" + count + ", desc='" + desc + '\'' + '}'; }}

基于表明编写接口实现。

@RestController@RequestMapping(value="/products") //通过这里配置使下面的映射都在/products下public class ProductController { private List<Product> productList; //初始化 public ProductController(){ productList = new ArrayList<Product>(); for (int i = 0; i < 10; i++) { Product product =new Product(); product.setId(i); product.setCount(i+10); product.setName("watch"+i); product.setDesc("watch desc"+i); productList.add(product); } } @ApiOperation(value="获取产品列表", notes="获取产品列表") @RequestMapping(value={""}, method= RequestMethod.GET) public List<Product> getProductList() { return productList; } @ApiOperation(value="获取产品详细信息", notes="根据url的id来获取产品详细信息") @ApiImplicitParam(name = "id", value = "产品ID", required = true, dataType = "Integer",paramType="path") @RequestMapping(value="/{id}", method=RequestMethod.GET) public Product getProduct(@PathVariable Integer id) { return productList.get(id); }}

基于Main方法启动。

@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}

访问http://localhost:8080/swagger-ui.html,自动天生的文档界面如图2-18所示。

图2-18 天生的文档界面

基于图2-18的界面进程测试,按“Try it out!
”按钮实行,如图2-19所示。

图2-19 在天生的文档上进行测试

访问http://localhost:8080/v2/api-docs可以获取接口的JSON描述文件,如图2-20所示。
可以直接到Swagger官网把JSON描述文件转换为YAML文件。

图2-20 转换为JSON的构造

HTTP协议的进化——HTTP/2

据W3Techs统计,截至2017年11月,排在前1千万名的网站中有20.5%的支持HTTP/2。
Chrome、Opera、Firefox、Internet Explorer 11、Safari、Amazon Silk和Edge浏览器都支持HTTP/2的标准化。
大多数主流浏览器都在2015年底之前添加了HTTP/2支持。

HTTP/2对HTTP/1.x进行了大量简化,使得性能得到了大幅度提升。
Akamai公司官网通过一个示例比拟了HTTP/1.1和HTTP/2在性能上的差距——并发要求379张图片,HTTP/1.1须要14.70s,相应韶光为3ms,而HTTP/2仅仅须要1.61s,相应韶光为6ms,如图2-21所示。

图2-21 比拟HTTP/1.1和HTTP/2的访问性能

我们都知道,在HTTP/1.x的协议中,浏览器在同一韶光对同一域名下的要求数量是有限定的,这会导致大量并发要求壅塞,这个问题也被称为线端壅塞(head-of-line blocking)。
同一域名下浏览器支持的连接数,如表2-4所示。
HTTP/1.1对不同浏览器连接数的限定不同,很多互联网公司为理解决这个问题,做了大量优化,包括建立多域名,通过CDN缓存大量静态资源等。

HTTP/2是基于二进制协议的,与HTTP/1.x这样的文本协议比较,显然二进制协议性能更高。
其余HTTP/2利用报头压缩,降落了网络开销。
HTTP/2将HTTP协议通信分解为二进制编码帧的交流,这些帧对应着特天命据流中的。
所有这些都在一个TCP连接内复用,这便是HTTP/2的多路复用机制(Multiplexing)。
Benjamin在2015年写的一篇文章中描述了一个大略的例子,如果只要求3个资源,从Web页面开始渲染到加载结束,HTTP/2比HTTP/1.1节省不少韶光,如图2-22所示。

表2-4 同一域名下浏览器支持的连接数

图2-22 HTTP/1.1和HTTP/2调用流程比拟

HTTP/2完备兼容HTTP/1.1的语义,HTTP/2和HTTP/1.1的大部分高等语法(例如方法、状态码、头字段和URI)都是相同的。

HTTP/1.1如果要实现长连接,须要设置Connection:keep-alive来掌握长连接韶光,超时就断开TCP连接。
只有在客户端发起要求的时候,做事器端才会相应。
以是就算一贯给做事器发送心跳包以坚持长连接,也不能用来推送,只有客户端不断发起要求给做事器端,做事器才会相应,这便是pull轮询的办法。

HTTP/2引入做事端推送模式,即做事端向客户端发送数据,如图2-23所示。
做事器可以对一个客户端要求发送多个相应,HTTP/2冲破了严格的要求-相应语义,支持一次要求-多次相应的形式。
由于现如今的Web界面丰富多彩,加载的资源每每非常多,做事端实际上已经知道要推送什么内容,但HTTP/1.x的语义只支持客户端发起要求、做事端相应数据。
HTTP/2改变了这种模式,只须要客户端发送一次要求,做事端便把所有的资源都推送到客户端。
做事器推送的缺陷是,在客户端已经缓存了资源的情形下可能会有冗余。
这个问题可以通过做事器提示(Server Hint)办理。

图2-23 HTTP/2推送模式

HTTP/2和Protobuf的组合——gRPC

gRPC源于被称为Stubby的Google内部项目,Google内部大量利用Stubby进行做事间通信。
作为gRPC的前身,Stubby大量依赖Google的其他根本做事,以是不太方便开放出来给社区利用。
随着HTTP/2的逐步成熟,2015年初Google开源了gRPC框架。
截至2017年12月,gRPC已经发布了1.7.3版本,并且被CNCF(云原生打算基金会)所收录。
gRPC在ETCD/Kubernetes上得到了大量利用。

gRPC是基于HTTP/2设计的,因此也继续了HTTP/2相应的诸多特性,这些特性使得其在移动设备上表现得更好,更节省空间、更省电。
gRPC目前供应的C、Java和Go措辞版本分别是grpc、grpc-java、grpc-go,个中C版本支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#。

说了这么多,gRPC到底能够给我们供应哪些上风呢?

· gRPC默认利用Protobuf进行序列化和反序列化,而Protobuf是已经被证明的高效的序列化办法,因此,gRPC的序列化性能是可以得到保障的。

· gRPC默认采取HTTP/2进行传输。
HTTP/2支持流(streaming),在批量发送数据的场景下利用流可以显著提升性能——做事端和客户端在吸收数据的时候,可以不必等所有的全收到后才开始相应,而是在吸收到第一条的时候就可以及时相应。
例如,客户端向做事端发送了一千条update,做事端不必等到所有吸收完毕才开始处理,而是一边吸收一边处理。
这显然比以前的类HTTP 1.1的办法供应的相应更快、性能更优。
gRPC的流可以分为三类:客户端流式发送、做事器流式返回,以及客户端/做事器同时流式处理,也便是单向流和双向流。
在我写这本书的时候,Dubbo 3.0正在酝酿中,个中一个显著的变革是新版本将以streaming为内核,而不再是2.0时期的RPC,目的是去掉统统壅塞。

· 基于HTTP/2协议很随意马虎实现负载均衡及流控的方案,可以利用Header做很多事情。

同时,gRPC也不是完美的。
比较于非IDL描述的RPC(例如Hession、Kyro)办法,定义proto文件是一个比较麻烦的事情,而且须要额外安装客户端、插件等。
其余HTTP/2比较于基于TCP的通信协议,性能上也有显著的差距。

下面通过一个大略的例子来理解一下gRPC的利用办法。
假设我们要开拓电商中的产品做事,通过id获取产品的信息,紧张步骤及实当代码如下。

(1)定义proto文件。

syntax = "proto3";//声明支持的版本是proto3 option java_multiple_files = true;//以外部类模式天生option java_package = "com.cloudnative.grpc";//声明包名,可选option java_outer_classname="ProductProtos";//声明类名,可选 message ProductRequest{ int32 id = 1;}message ProductResponse { int32 id = 1; string name = 2; string price = 3;} service ProductService{ rpc GetProduct(ProductRequest) returns(ProductResponse);}

(2)天生干系类。
可以采取Protobuf中先容的方法,在命令行实行protoc天生干系代码。
如果利用Maven,则可以通过Maven插件实现。

<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:3.5.1:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.8.0:exe:${os.detected. classifier}</pluginArtifact> <protocExecutable>/usr/local/bin/protoc</protocExecutable> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins></build>

在pom.xml中配置,并且实行mvn compile命令会在target/generated-sources中天生干系类,可以将干系类移到src /main/java目录下备用。

(3)做事端实当代码。
一是,实现ProductService。

public class ProductService extends ProductServiceGrpc.ProductServiceImplBase{ private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); @Override public void getProduct(ProductRequest request, StreamObserver<ProductResponse> responseObserver) { logger.info("吸收到客户真个信息:"+request.getId()); ProductResponse responsed; if (111==request.getId()){ responsed=ProductResponse.newBuilder().setId(111).setName ("dddd").build(); }else { responsed=ProductResponse.newBuilder().setId(0).setName("---").build(); } responseObserver.onNext(responsed); responseObserver.onCompleted(); }}

二是,实现server代码。

public class GRPCServer{ private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); private final int port; private final Server server; public GRPCServer(int port){ this.port=port; this.server = ServerBuilder.forPort(port) .addService(new ProductService()) .build(); } / Start serving requests. / public void start() throws IOException { this.server.start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { // Use stderr here since the logger may has been reset by its JVM shutdown hook. logger.info(" shutting down gRPC server since JVM is shutting down"); GRPCServer.this.stop(); logger.info(" server shut down"); } }); } / Stop serving requests and shutdown resources. / public void stop() { if (server != null) { server.shutdown(); } } / Await termination on the main thread since the grpc library uses daemon threads. / private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } / Main method. This comment makes the linter happy. / public static void main(String[] args) throws Exception { GRPCServer server = new GRPCServer(8888); server.start(); server.blockUntilShutdown(); } }

(4)客户端实当代码。

public class GRPCClient { private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8888) .usePlaintext(true) .build(); ProductServiceGrpc.ProductServiceBlockingStub blockStub=ProductServiceGrpc.newBlockingStub(channel); ProductResponse response=blockStub.getProduct(ProductRequest.newBuilder().setId(111).build()); logger.info(response.getName()); response=blockStub.getProduct(ProductRequest.newBuilder().setId(2).build()); logger.info(response.getName()); } }

上面是一个大略的实现,关于流式RPC可以参考官方的例子。

来源 公众年夜众号 技能琐话 | 王启军

如有侵权请联系删除

相关文章

Python编程从入门到精通,探索编程之美

编程已经成为现代社会的一项基本技能。Python作为一种简单易学、功能强大的编程语言,在我国教育领域备受关注。本文将从Python...

网站推广 2025-03-02 阅读1 评论0

Scum07代码编程之美与适用方法

编程已成为当今社会不可或缺的技能之一。Scum07代码作为一款经典的编程语言,在我国众多程序员中备受推崇。本文将深入解析Scum0...

网站推广 2025-03-02 阅读1 评论0

Linux环境下的前端代码运行优化与步骤

前端技术逐渐成为软件开发的核心。Linux操作系统因其稳定性、安全性、开放性等特点,成为众多开发者和企业青睐的运行环境。本文将从L...

网站推广 2025-03-02 阅读1 评论0