Para ejemplos de proyectos, consulte: kotlin-grpc
1. Dependencias de importación:
import com.google.protobuf.gradle.*
plugins {
id("org.springframework.boot") version "2.3.1.RELEASE"
id("io.spring.dependency-management") version "1.0.9.RELEASE"
id("org.asciidoctor.convert") version "1.5.9.2"
kotlin("jvm") version "1.6.0"
kotlin("plugin.spring") version "1.6.0"
id("com.google.protobuf") version "0.9.2"
}
repositories {
mavenCentral()
}
group = "com.whrss.kotlin-grpc"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8
sourceSets.main {
java.srcDirs("src/main/kotlin")
}
extra["spring-restdocs.version"] = "2.0.5.BUILD-SNAPSHOT"
val snippetsDir by extra {
file("build/generated-snippets") }
dependencies {
implementation("com.google.protobuf:protobuf-java:3.22.2")
implementation("io.grpc:grpc-protobuf:1.53.0")
implementation("com.google.protobuf:protobuf-kotlin:3.22.2")
implementation("io.grpc:grpc-kotlin-stub:1.3.0")
implementation("io.grpc:grpc-netty:1.56.1")
implementation("io.grpc:grpc-all:1.56.1")
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.19.4"
}
plugins {
id("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:1.40.1"
}
id("grpckt") {
artifact = "io.grpc:protoc-gen-grpc-kotlin:1.3.0:jdk8@jar"
}
}
// Enable Kotlin generation
generateProtoTasks {
all().forEach {
it.plugins {
id("grpc")
id("grpckt")
}
} }}
2. Establecer prototipo
Pon proto
el archivo src/mian/proto
en el directorio.
syntax = "proto3";
import "google/api/annotations.proto";
option java_multiple_files = true;
package hello_world.v1;
service HelloWorldService{
rpc GetUserInfo (GetUserRequest) returns (GetUserReply) {
option (google.api.http) = {
get: "/api/v1/users"
};
}
}
message GetUserRequest{
// 用户showId
string userId = 1;
}
message GetUserReply{
// 用户showId
string userId = 1;
}
implementar./gradlew clean build
Si la compilación es exitosa build/generated/source/proto/main
, se generarán los archivos correspondientes en el programa y el paquete se puede importar directamente en el programa grpc
.grpckt
java
3. Lado del servidor
escribe unservice
import hello_world.v1.GetUserReply
import hello_world.v1.GetUserRequest
import hello_world.v1.HelloWorldServiceGrpcKt
class Service : HelloWorldServiceGrpcKt.HelloWorldServiceCoroutineImplBase() {
override suspend fun getUserInfo(request: GetUserRequest) : GetUserReply {
println("getItemStatistics exec")
return GetUserReply.newBuilder()
.setUserId(request.userId)
.build()
}
}
main
Introducir inicio en la entrada
import io.grpc.ServerBuilder
fun main() {
helloServer()
}
fun helloServer() {
val helloService = Service()
val server = ServerBuilder
.forPort(15001)
.addService(helloService)
.build()
Runtime.getRuntime().addShutdownHook(Thread {
server.shutdown()
server.awaitTermination()
})
server.start()
println("server start")
server.awaitTermination()
println("server restart")
}
4. Lado del cliente
import hello_world.v1.GetUserRequest
import hello_world.v1.HelloWorldServiceGrpc
import io.grpc.ManagedChannelBuilder
fun main() {
val channel = ManagedChannelBuilder.forAddress("localhost", 15001).usePlaintext()
val stub = HelloWorldServiceGrpc.newBlockingStub(channel.build())
val response = stub.getUserInfo(GetUserRequest.newBuilder().setUserId("0").build())
println(response)
}
Cinco, algunos hoyos
Algunas dependencias de io.grpc y com.google están relacionadas. Si hay una gran diferencia entre las versiones dependientes, provocará un error de ejecución. Por ejemplo, antes usé una dependencia muy antigua de Google: com.google.code.google-collections:google-collect:snapshot-20080530
, lo que provocó el mensaje cuando mi programa se estaba ejecutando:
Exception in thread "main" java.lang.NoSuchMethodError: 'void com.google.common.base.Preconditions.checkArgument(boolean, java.lang.String, char, java.lang.Object)'
at io.grpc.Metadata$Key.validateName(Metadata.java:754)
at io.grpc.Metadata$Key.<init>(Metadata.java:762)
at io.grpc.Metadata$Key.<init>(Metadata.java:671)
at io.grpc.Metadata$AsciiKey.<init>(Metadata.java:971)
at io.grpc.Metadata$AsciiKey.<init>(Metadata.java:966)
at io.grpc.Metadata$Key.of(Metadata.java:708)
at io.grpc.Metadata$Key.of(Metadata.java:704)
at io.grpc.internal.GrpcUtil.<clinit>(GrpcUtil.java:99)
at io.grpc.netty.Utils.<clinit>(Utils.java:83)
at io.grpc.netty.UdsNettyChannelProvider.isAvailable(UdsNettyChannelProvider.java:34)
at io.grpc.ManagedChannelRegistry$ManagedChannelPriorityAccessor.isAvailable(ManagedChannelRegistry.java:211)
at io.grpc.ManagedChannelRegistry$ManagedChannelPriorityAccessor.isAvailable(ManagedChannelRegistry.java:207)
at io.grpc.ServiceProviders.loadAll(ServiceProviders.java:68)
at io.grpc.ManagedChannelRegistry.getDefaultRegistry(ManagedChannelRegistry.java:101)
at io.grpc.ManagedChannelProvider.provider(ManagedChannelProvider.java:43)
at io.grpc.ManagedChannelBuilder.forAddress(ManagedChannelBuilder.java:39)
at com.ck567.kotlingrpc.ClientKt.main(Client.kt:9)
at com.ck567.kotlingrpc.ClientKt.main(Client.kt)
No puede encontrar problemas específicos en Google, puede prestar atención para ver si hay otras dependencias de com.google en el proyecto.
Las versiones de dependencia anteriores se basan en las versiones correspondientes spring boot
y kotlin
. Si su versión no coincide, es posible que deba descartarla, pero el problema no debería ser demasiado grande. Usando el almacén espejo de Alibaba Cloud, puede buscar directamente imágenes espejo aquí para verificar las versiones compatibles.
Hay un problema con el empaquetado de Gradle. La razón del problema es que Bintray/jcenter
se ha deshabilitado. Para confiar en estos complementos de Kotlin, puede usar las dependencias en la imagen de Alibaba Cloud .
A problem occurred configuring root project 'yybs-backend'.
> Could not resolve all artifacts for configuration ':classpath'.
> Could not resolve org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.6.0.
Required by:
project : > org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.6.0 > org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0
project : > org.jetbrains.kotlin.plugin.spring:org.jetbrains.kotlin.plugin.spring.gradle.plugin:1.6.0 > org.jetbrains.kotlin:kotlin-allopen:1.6.0
> Could not resolve org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.6.0.
..........
> sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Busque el ~/.gradle
directorio correspondiente, cree o modifique init.gradle
el contenido de la siguiente manera
allprojects {
repositories {
maven {
url 'https://maven.aliyun.com/repository/public/'
}
maven {
url 'https://maven.aliyun.com/repository/jcenter/'
}
all {
ArtifactRepository repo ->
if (repo instanceof MavenArtifactRepository) {
def url = repo.url.toString()
if (
url.startsWith('https://repo.maven.apache.org/maven2/')
|| url.startsWith('https://repo.maven.org/maven2')
|| url.startsWith('https://repo1.maven.org/maven2')
|| url.startsWith('https://jcenter.bintray.com/')
|| url.startsWith('https://plugins.gradle.org/')
) {
//project.logger.lifecycle "Repository ${repo.url} replaced by $REPOSITORY_URL."
remove repo
}
}
}
}
buildscript {
repositories {
maven{
url 'https://maven.aliyun.com/repository/public/'}
maven {
url 'https://maven.aliyun.com/repository/jcenter/'
}
maven {
url 'https://maven.aliyun.com/repository/gradle-plugin/'
}
all {
ArtifactRepository repo ->
if (repo instanceof MavenArtifactRepository) {
def url = repo.url.toString()
if (
url.startsWith('https://repo1.maven.org/maven2')
|| url.startsWith('https://jcenter.bintray.com/')
|| url.startsWith('https://plugins.gradle.org/')
) {
//project.logger.lifecycle "Repository ${repo.url} replaced by $REPOSITORY_URL."
remove repo
}
}
}
}
}
}
--grpckt_out: protoc-gen-grpckt: Plugin failed with status code 1
Execution failed for task ':generateProto'.
> protoc: stdout: . stderr: Exception in thread "main" java.lang.VerifyError: Uninitialized object exists on backward branch 71
Exception Details:
Location:
com/squareup/kotlinpoet/TypeSpec.<init>(Lcom/squareup/kotlinpoet/TypeSpec$Builder;Lcom/squareup/kotlinpoet/TagMap;Lcom/squareup/kotlinpoet/OriginatingElementsHolder;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @118: goto
Reason:
Error exists in the bytecode
Bytecode:
0000000: 1504 057e 9900 0b2b c003 44b8 034a 4d15
0000010: 0407 7e99 007e 2bb6 00de c000 9a2b b600
0000020: c4c0 009c 3a06 3a0f 0336 0719 063a 08bb
0000030: 0152 59b7 01c3 c000 9a3a 0903 360a 1908
0000040: b901 5c01 003a 0b19 0bb9 0161 0100 9900
0000050: 2b19 0bb9 0165 0100 3a0c 190c 3a0d 0336
0000060: 0e19 0dc0 0002 b600 dfc0 009c 3a0d 1909
0000070: 190d b800 a257 a7ff d119 09c0 016e 3a10
0000080: 190f 1910 c000 9cb8 0172 b803 50c0 0008
0000090: 4e2a 2b2c 2db7 0352 b1
Stackmap Table:
same_frame(@15)
full_frame(@71,{
UninitializedThis,Object[#144],Object[#218],Object[#8],Integer,Object[#857],Object[#156],Integer,Object[#156],Object[#154],Integer,Object[#350],Top,Top,Top,Object[#154]},{})
same_frame(@121)
full_frame(@145,{
UninitializedThis,Object[#144],Object[#218],Object[#8],Integer,Object[#857]},{})
at io.grpc.kotlin.generator.GrpcClientStubGenerator.generateStub(GrpcClientStubGenerator.kt:111)
at io.grpc.kotlin.generator.GrpcClientStubGenerator.generate(GrpcClientStubGenerator.kt:100)
at io.grpc.kotlin.generator.ProtoFileCodeGenerator.generateCodeForFile(ProtoFileCodeGenerator.kt:50)
at io.grpc.kotlin.generator.GeneratorRunner.generateCodeForFile(GeneratorRunner.kt:44)
at io.grpc.kotlin.generator.protoc.AbstractGeneratorRunner.mainAsProtocPlugin(AbstractGeneratorRunner.kt:56)
at io.grpc.kotlin.generator.protoc.AbstractGeneratorRunner.doMain(AbstractGeneratorRunner.kt:87)
at io.grpc.kotlin.generator.GeneratorRunner.main(GeneratorRunner.kt:28)
--grpckt_out: protoc-gen-grpckt: Plugin failed with status code 1.
versión de actualización java
, actualicé a la últimajdk-8u221
Si tiene alguna pregunta, deje un mensaje, no seré tacaño si puedo ayudar.