likes
comments
collection
share

SpringBoot Kotlin 集成和使用 Protobuf

作者站长头像
站长
· 阅读数 45

环境版本

不同的环境配置参数可能区别较大,请酌情参考。

插件或依赖版本号
SpringBoot2.7.10
Gradle7.5.1
Protobuf Gradle Plugin0.9.2
Protobuf Java3.21.9
Protoc3.21.9
Grpc1.53.0

项目是使用 IDEA 创建的 Spring Web 项目,语言 Kotlin,构建 Gradle

Protobuf 手动配置

Protobuf 的目的是将数据序列化,它提供了完善的编码工具:Protoc,可以将 .proto 定义的文件方便地转换为所需语言的类文件。

比如:Kotlin 使用 Protobuf,手动配置的流程如下:

创建 .proto 文件
运行 protoc 命令将 .proto 文件转换为 .kt 文件
使用 .kt 类方法进行序列化

但是,实践结果是生成的 .kt 文件有错误,可能是 Kotlin 版本问题。 用起来也不是很方便,所以采用 gradle plugin 的方式自动管理包和编译Proto。

添加插件和依赖

在 build.gradle.kts 中配置 Protobuf 需要的插件和依赖。

添加 protobuf gralde plugin

plugins {
    ... 
    id("com.google.protobuf") version "0.9.2"
}

该插件帮助管理 protoc 和完成文件转换。

Protobuf Gradle Plugin 的源码地址: github.com/google/prot…

添加 Protobuf 的依赖包

dependencies {
	...
	implementation("com.google.protobuf:protobuf-java:3.21.9")
	implementation("io.grpc:grpc-protobuf:1.53.0")
	implementation("io.grpc:grpc-stub:1.53.0")
}

配置 Protobuf 插件

protobuf {
	// 配置 protoc
    protoc {
        artifact = "com.google.protobuf:protoc:3.21.9"
    }
    // 配置 grpc
    plugins {
    	// 这里需要加 id,旧版本可能是这样: grpc {}
        id("grpc"){
            artifact = "io.grpc:protoc-gen-grpc-java:1.53.0"
        }
    }
    // 配置 gradle task
    generateProtoTasks {
        ofSourceSet("main").forEach {
            it.plugins {
                id("grpc") { }
            }
        }
    }
}

编写 .proto 文件

文件位置

在 src/main目录下新建目录 proto,然后在该目录下新建包名和 .proto 文件。 示例目录结构如下:

  src
	└─ main
	    ├─kotlin
	    │  └─cn.test.proj
	    ├─proto
	    │  └─cn.test.proj
	    │          Param.proto

	    └─resources

proto 与 kotlin 在同一级,.proto 文件在相同的包下。

proto 文件编写

这里是简单示例,详细内容,请参考 proto 官方文档。

syntax = "proto3";
package cn.test.proj;
message Person {
  string id = 1;
  string name = 2;
}

package 值与目录中的包名对应

使用方法

生成 Proto 对象

在 IDEA 右侧 Gradle 窗口,执行 Tasks - other - generateProto 任务,生成 Proto 对象。

使用 Proto 对象

不像手动运行 protoc 命令会生成 .kt 文件。运行 generateProto task 之后,项目文件中没有看到对应的 .kt 文件生成,但是可以像使用 Kotlin 对象一样使用 proto 对象。

参照上文示例,我们在 Param.proto 中定义了一个 Person 对象,如果使用 Okhttp3 请求网络服务,参数是 Person,响应参数也是 Person 示例代码如下:


private const val CONTENT_TYPE = "application/x-protobuf"

fun request(){
	val requestPerson = Param.Person.newBuilder().apply{
		id = "testid"
		name = "Peter"
	}.build()
	val requestBytes = requestPerson.toByteArray() // 序列化
	val requestBody = requestBytes.toRequestBody(CONTENT_TYPE.toMediaType())
	... 
	// Okhttp 请求
	// header 中添加 "Content-Type" = CONTENT_TYPE
	// 请求响应结果 response: Response
	...
	val responseBytes = response.body?.bytes()
	val responsePerson = Param.Person.parseFrom(responseBytes) // 反序列化
}

转载自:https://juejin.cn/post/7223973532354003000
评论
请登录