protocol buffer是什么?
protocol buffer是google定义的一种传输格式协议,类似json和xml,它的
优势在于它的传输体积小,解析速度快,如果传输的数据特别大,它传输的
速度及解析的速度是json和xml解析的指数级别。之前有记得看过一本书,
是用Gzip压缩数据来传输,从而实现传输体积小的目的,但是它有一个缺点
就是解压缩的时候特别耗计算机cpu性能。而protocol buffer它是通过对对
象进行序列化和反序列化的。
protocol buffer序列化和反序列化的原理?
本质还是对象与字节之间转换的传输,比如入参通过把字节转换成对象,
通过双方定义的格式,而出参是通过将对象转换成字节。也就是在网络中
传输还是通过字节的形式,可以想象一下字母转换成0101010001类似的格
式。笔者对四层tcp/ip网络协议,七层osi网络协议不是特别理解,大家
有特别懂的,私信我一下,万分感激。字节具体可以理解成二进制串。类似
映射键值对那种,中间加个长度。如k1-1-v1-k2-6-v2-…(这一块后面我再
仔细研究,深入它为什么解析速度会这么快的原理)
springcloud是怎么集成protocol buffer的?(重点描述!!)
因为用spring全家桶的原因,eureka作为配置和注册发现中心,feign消费方
是怎么通过protobuf来调用生产方的呢?
1.下载protobuf
https://github.com/google/protobuf/releases
选择protoc-xxx-win32.zip下载
2.将解压出来的protoc.exe放在C:\Windows\System32目录下,
同时在windows环境变量中新建proto_path变量,值为C:\Windows\System32\protoc.exe的路径
3.在所使用的proto文件路径下打开cmd窗口执行以下命令
4.执行protoc –version命令检查是否安装成功
protoc –version
5.然后写proto文件,生成一个RetreatCouponReqConvert.proto文件
文件内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14syntax = "proto2";
package com.carlife.coupon.proto.model; //输出路径
option java_outer_classname = "RetreatCouponReqConvertModel"; //输出的类名
message RetreatCouponReqConvert{
required string orderId = 1 ;
required string couponCode = 2 ;
required string srcPartnerId = 3 ;
required string sign = 4 ;
required string caller = 5 ;
required string noise = 6 ;
required string reqId = 7 ;
}
这个文件对应的java文件如:RetreatCouponReqConvert.java
内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45@Data
public class RetreatCouponReqConvert extends BaseReq implements Serializable {
private static final Long serialVersionUID = 5797586702757567145L;
@NotBlank
@ApiModelProperty(value = "订单id",required = true)
private String orderId; // required
@NotBlank
@ApiModelProperty(value = "券码",required = true)
private String couponCode; // required
@NotBlank
@ApiModelProperty(value = "退款商户ID",required = true)
private String srcPartnerId;
/**
* 签名
*/
@ApiModelProperty(value = "【必填】签名")
@NotBlank
private String sign;
/**
* 调用者,和签名一起传入,用于校验
*/
@ApiModelProperty(value = "【必填】调用者,和签名一起传入,用于校验")
@NotBlank
private String caller;
/**
* 随机数(例如 访问时间戳)
*/
@ApiModelProperty(value = "【必填】随机数(例如 访问时间戳)")
@NotBlank
private String noise;
/**
* 访问请求ID
*/
@ApiModelProperty(value = "【必填】访问请求ID")
@NotBlank
private String reqId;
}
然后跑一下这个文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package com.carlife.common.utils;
import java.io.IOException;
/**
* protoc.exe -I=proto的输入目录 --java_out=java类输出目录 proto的输入目录包括包括proto文件
*
* @author Administrator
*
*/
public class GenerateClass {
public static void main(String[] args) throws IOException {
String protoFile = "RetreatCouponReqConvert.proto";
String path = "D:/cashier-master/cashier-master/cashier-sdk/src/main/java/com/carlife/coupon/proto";
String out = "D:/cashier-master/cashier-master/cashier-sdk/src/main/java";
String strCmd = "C:/Windows/System32/protoc.exe -I=" + path +
" --java_out=" + out + " " + path + "/" + protoFile;
System.out.println(strCmd);
Runtime.getRuntime().exec(strCmd);
System.out.println("完成");
}
}
如果RetreatCouponReqConvertModel.java没有生成,粘strCmd出来到git命令行窗口跑,找下原因
依赖jar包1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
feign(调用者)端在启动如SpringApplication.java启动文件同级目录下增加以下配置文件
内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35package com.carlife;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
import org.springframework.cloud.netflix.feign.support.SpringDecoder;
import org.springframework.cloud.netflix.feign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
@Configuration
public class ProtoFeignConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
@Bean
public Encoder springEncoder(){
return new SpringEncoder(this.messageConverters);
}
@Bean
public Decoder springDecoder(){
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
}
}
生产者(被调用者)端同样在启动如SpringApplication.java启动文件同级目录下增加以下配置文件
内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.carlife.coupon;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
@Configuration
public class ProtoBufServerConfig {
@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
最后一步,编写消费接口和生产接口
消费接口类似的内容如下:1
2@RequestMapping(method = RequestMethod.POST, value = "/retreatCouponPb", consumes = "application/x-protobuf",produces="application/x-protobuf")
RetreatCouponRspModel.RetreatCouponRsp retreatCouponPb(RetreatCouponReqConvertModel.RetreatCouponReqConvert req);
生产接口类似的内容如下:1
2
3
4
5
6
7
8
9
10@PostMapping(value = "retreatCouponPb")
@ResponseBody
public RetreatCouponRspModel.RetreatCouponRsp retreatCouponPb(@RequestBody RetreatCouponReqConvertModel.RetreatCouponReqConvert req) {
String couponCode = req.getCouponCode();
System.out.println("couponCode : "+couponCode);
RetreatCouponRspModel.RetreatCouponRsp.Builder builder = RetreatCouponRspModel.RetreatCouponRsp.newBuilder();
builder.setMsg("-----OK----");
builder.setCode(RspMsgCodeEnum.SUCCESS.getValue());
return builder.build();
}
然后用下面来调用消费接口即可,如下:1
2
3
4
5
6
7
8
9@PostMapping(value = "testProto")
public void testProto(@RequestBody RefundOrderReq refundOrderReq) {
RetreatCouponReqConvertModel.RetreatCouponReqConvert build = RetreatCouponReqConvertModel.RetreatCouponReqConvert.newBuilder()
.setCaller("123").setCouponCode("888888888888888888")
.setNoise("123").setOrderId("123").setReqId("123")
.setSign("123").setSrcPartnerId("123").build();
RetreatCouponRspModel.RetreatCouponRsp retreatCouponRsp = couponProviderV2.retreatCouponPb(build);
System.out.println("code = "+retreatCouponRsp.getCode()+"msg = "+retreatCouponRsp.getMsg());
}
以上可能不是写的很详细,深感抱歉,但希望能帮助到有需要的人。