需求
需要一个在稳定网络环境里高性能且开发和部署成本较小,且多平台,且对视频传输和消息订阅和推送的支持比较好的, 一套环境
先说结论因为结论先得到的, 问AI了, 发现一个新东西gRPC ,看了下非常好。
再说过程,首先存在订阅和推送的场景所以传统的http/1.1就都不行,之前做过前台的长连接来实现页面实时k线图,百度的一个什么前台插件,忘了。一来讨厌前端二来gRPC基于的http/2.0 原生支持这些场景,甚至发视频的时候每个视频帧的通信都不需要客户端返回,貌似能节省最多一半的cpu和网络时间。
github上找了springboot + gRPC的项目
https://github.com/grpc-ecosystem/grpc-spring/
开始
Gradle用来替代maven,正如maven替代Ant,没用过。Srping 不太会用不喜欢
git clone https://github.com/grpc-ecosystem/grpc-spring.git
运行例子
文档里是
./gradlew :example:local-grpc-server:bootRun
老子找了半天example来自哪,找不到。试了下
./gradlew :examples:local-grpc-server:bootRun
深感震惊,居然可以
./gradlew :exa:local-grpc-server:bootRun
也可以,荒唐
AI说
在Gradle中,可以使用拼写不完整的单词进行任务或配置的原因是其基于Groovy的领域特定语言(DSL)具有高度灵活性和容错能力
易用性过高导致严谨性没有了, 我去搜exa是期望找到些东西的,但其实他可以代表examples。这是不可接受的
幂等原则的类似,不同的命令不应该有同样的输出,一一对应是最严谨的
约定大于配置是个非常的,过于提高易用性的东西,提高了学习成本,必然你得知道约定了什么,而配置就可以没有学习成本,遇到的东西都已经配置好了,全局搜索就可以明白所有东西。我讨厌约定
感觉到了之前玩nodejs的痛苦经历,为了照顾新手把东西都弄得看起来很简单,把东西都封起来张三李四王二麻子全都搞一个封装 规则 约定,github里完全找不到两个用同一套工具的项目,乱成一锅粥。好像最佳实践这样的东西不存在一样
我觉得优秀的工具或者框架,应该不看文档只看两个例子就可以完全上手整套流程,文档只需要一些枚举值
现在很多甚至主流的工具,来用我吧用我你就可以当白痴也能开发,还能比别人写的代码少就能完成一样的功能,
但是你原理都不明白成了某个工具使用者而不是开发。写个helloworld打包一个G,
这不好,开发是要解决所有问题的,任何一个环节的的问题,如何能这样呢,是你了解所有东西,一个G的helloworld你不可能了解,他有问题了你完全解决不了
触类旁通是一个可能最重要的能力,但工具使用者做不到。精通一个东西从内到外,才能解锁这个能力,浮于表面看不到本质是没有用的
spring开了这个头,万恶之首,追踪代码变成了很难的事,把一个准确的严肃的东西变成了卖弄雕虫小技
吐槽归吐槽,也不能因为不好用不喜欢就不用他,开始玩,不,折腾他
./gradlew tasks --all 可以看到所有命令,太多的话可以
./gradlew :ex:local-grpc-server:tasks 可以看到某个moudle下的命令
bootRun是 spring-boot-gradle-plugin 提供的
bootJar就可以生成 可以直接 java -jar xx.jar 运行的jar了。
生成目录:\local-grpc-server\build\libs
idea里gradle的配置
没看怎么配置镜像仓库,梯子直接连美国完事,
build完成后
这个窗口才会有内容,原来以为maven的这个优点居然没继承,看了下比maven的好
gRPC使用proto是为了通信的java input output对象的序列化 (google自家的)
如何编写.proto文件:
https://protobuf.dev/programming-guides/proto3/
编辑 .proto 之后执行 generateProto 得到一堆java文件
build命令报错
https://cloud.tencent.com/developer/article/1764107
代码里的空格报错方块问号。 改了之后空格报错为· ,之后把那段注释删掉,报错里还有那段注释。 (看吧,这就是不严谨的结果) (执行build有个提示Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.)
build不通过,直接bootRun ,跑起来了,bootRun会把以来的task都先跑了,没跑build 看来build已经不在生命周期里了,但idea的插件里tasks列表里还有这个命令。那就不管他
这是一个常识,写的简单易懂
https://blog.51cto.com/u_16099230/10254798
但是抄袭嫌疑
https://www.baeldung.com/java-grpc-streaming
至此
例子跑通了
是最简单的一问一答 , http/1.1完全可以做的
- 运行命令2,3
- 打开 client 用@RequestMapping(“/”) 暴露的http://localhost:8080/
- 通信成功
开始写steam的例子
Server streaming RPC
新增 .proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "net.devh.boot.grpc.examples.lib";
option java_outer_classname = "SteamTransferProto";
service SteamTransfer {
//订阅某个传感器的观测值 监视
rpc monitor (MonitorRequest) returns (stream MonitorReply) {
}
}
message MonitorRequest {
int32 monitSomeThing = 1;
}
message MonitorReply {
int32 observedValue = 1;
}
服务端一秒返回一次,15次之后结束
@GrpcService
public class StreamTransferServerService extends SteamTransferGrpc.SteamTransferImplBase {
@Override
public void monitor(MonitorRequest req, StreamObserver<MonitorReply> responseObserver) {
int a = req.getMonitSomeThing();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i<15;i++ ) {
if (null != responseObserver) {responseObserver.onNext(MonitorReply.newBuilder().setObservedValue(
i +new Random().nextInt(10)
).build());
System.out.println("send to client");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
responseObserver.onCompleted();
}
}).start();
}
}
客户端
@GrpcClient("local-grpc-server")
private SteamTransferGrpc.SteamTransferStub steamTransferStub;
public int steamTransfer(int one){
steamTransferStub.monitor(MonitorRequest.newBuilder().setMonitSomeThing(one).build(), new StreamObserver<MonitorReply>() {
@Override
public void onNext(MonitorReply value) {
System.out.println(Thread.currentThread().getName() + " observer value: " + value.getObservedValue());
}
@Override
public void onError(Throwable t) {
System.out.println("error:" + t.getLocalizedMessage());
}
@Override
public void onCompleted() {
System.out.println("onCompleted:");
}
});
return 1;
}
Client streaming RPC
暂时用不着