SpringBoot + Kotlin 中使用 GRPC 进行服务通信

这篇具有很好参考价值的文章主要介绍了SpringBoot + Kotlin 中使用 GRPC 进行服务通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

示例项目见:kotlin-grpc

一、导入依赖:

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")  
            }  
        }    }}

二、设置Proto

proto 文件放在 src/mian/proto 目录下

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;  
}

执行 ./gradlew clean build

build成功则会在 build/generated/source/proto/main 下生成对应的 grpcgrpcktjava 文件
在程序中可以直接导包引入
SpringBoot + Kotlin 中使用 GRPC 进行服务通信,kotlin,springboot,grpc

三、Server端

写一个 service

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 入口引入启动

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")  
}

四、Client 端

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)  
}

五、一些坑

io.grpc 和 com.google的一些依赖是有关联的,如果依赖版本之间有巨大差异,是会导致运行错误的。比如我之前使用到了一个 google 的一个特别老的依赖:com.google.code.google-collections:google-collect:snapshot-20080530,导致了我程序运行时提示:

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)

在google是发现不了具体的问题的,可以注意一下,在项目中查看下是否有别的com.google的依赖。

上面的依赖版本都是基于对应 spring bootkotlin 版本的,如果你的版本不适配,可能也需要折腾一下,但问题应该不是很大。使用阿里云的镜像仓库,可以直接在这里搜索镜像,查看支持的版本。


gradle 打包出现问题,问题原因是Bintray/jcenter 已停用,要依赖这些 kotlin 插件可以使用阿里云的镜像中的依赖。

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

找到对应的~/.gradle 目录,创建或修改 init.gradle 内容为下面的内容

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.

升级 java 版本,我升级到了最新的 jdk-8u221

如有问题,欢迎留言,能帮到的地方,我不会吝啬。文章来源地址https://www.toymoban.com/news/detail-574161.html

到了这里,关于SpringBoot + Kotlin 中使用 GRPC 进行服务通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • NestJS使用gRPC实现微服务通信

    代码仓库地址:https://github.com/zeng-jc/rpc-grpc-practice 1.1 基本概念 gRPC 基于 Protocol Buffers(protobuf)作为接口定义语言(IDL),意味着你可以使用 protobuf 来定义你的服务接口,gRPC生成的代码可以用于多种语言(C++, Java, Python, Go, C#, Ruby, Node.js),所以使用gRPC就能实现跨语言之间进

    2024年02月04日
    浏览(44)
  • 【Kotlin】类的继承 ② ( 使用 is 运算符进行类型检测 | 使用 as 运算符进行类型转换 | 智能类型转换 | Any 超类 )

    在 Kotlin 中 , 如果不确定一个 实例对象的类型 , 可以 使用 is 运算符进行判定 , 使用方法 上述用法可以判定 实例对象 是否是 判定类型 , 如果是 返回 true , 反之 返回 false ; 代码示例 : 在下面的代码中 , 调用 student is Person 判断 student 对象是否是 Person 类型 ; 执行结果 : 将 子类

    2024年02月03日
    浏览(48)
  • 『gRPC 服务』使用 Postman 对 .NET Core 的 gRPC 服务进行调试测试

    📣读完这篇文章里你能收获到 .NET Core反射gRPC 使用Postman调用gRPC 感谢点赞+收藏,避免下次找不到~ 项目中需 包含 Grpc.AspNetCore.Server.Reflection 包,可在Nuget安装 在 Program.cs 中注册反射: AddGrpcReflection 用于注册启用反射的服务。 MapGrpcReflectionService 用于添加反射服务终结点。 P

    2024年02月15日
    浏览(51)
  • Kotlin与H5通信的实现方式

    要知道kotlin和html是两种不同的程序,并且一个运行在手机的android端,一个运行在服务器的后端程序,让这两种不同运行环境的不同编程语言进行通信,需要用到addJavascriptInterface方法,来进行数据的访问和方法的调用 下面开始一些环境准备工作 1编写后端程序并且在服务器上

    2023年04月18日
    浏览(92)
  • SpringBoot如何使用MultipartFile进行文件上传保存到服务器本地

    之前一直都是用的别人封装好的文件上传方法,这次想自己写一个特别简单的,文件上传方法,非常适合新手观看… 首先需要Springboot需要有Web依赖,就是下面这个依赖 依赖导完了,下面就直接是代码,大家看一下 到这里文件上传的解释都在代码里面,下面如果报文件过大的报错还需

    2024年02月13日
    浏览(68)
  • docker—springboot服务通信

    1、host 步骤: host文件增加域名解析: application.yml: application.yml 中,连接方式使用是服务镜像名,而不是ip。 如果在使用的过程中修改了Dockerfile, 一定要把之前的镜像删掉! https://blog.csdn.net/shang_0122/article/details/120473681 使用Docker Compose部署SpringBoot应用

    2024年02月15日
    浏览(39)
  • SpringBoot集成WebSocket实现客户端与服务端通信

    话不多说,直接上代码看效果! 一、服务端: 1、引用依赖 2、添加配置文件 WebSocketConfig 3、编写WebSocket服务端接收、发送功能   声明接口代码:   实现类代码: 4、如果不需要实现客户端功能,此处可选择前端调用,奉上代码 二、客户端: 1、引用依赖 2、自定义WebSocket客

    2024年01月23日
    浏览(54)
  • SpringBoot集成Dubbo启用gRPC协议

    本文记录下SpringBoot集成Dubbo启用gRPC协议,以及与原生 gRPC 在代码编写过程中的区别。 下面还有投票,帮忙投个票👍 2023.6.30 补充:Dubbo 官方文档开放,为开发者使用提供友好的支持。 Dubbo 在 2.7.5 版本开始支持原生 gRPC 协议,对于计划使用 HTTP/2 通信或者期望 gRPC 协议支持服

    2023年04月12日
    浏览(48)
  • 正确使用Kotlin动态代理

    前言: 说到设计模式,想必很多人都会想到,常见的设计模式之一的动态代理。特别是,对很多中高级Android程序员而言,更是如此。因为著名的网络框架Retrofit,关于网络调用部分,就是采用动态代理,将网络请求,委托给OkHttp实现。但在使用Kotlin语言,来实现动态代理时,

    2024年02月04日
    浏览(38)
  • kotlin的copy使用

    笔者专注于Android安全领域, 欢迎关注个人的微信公众号《Android安全工程》(可点击进行扫码关注)。个人微信公众号主要围绕 Android 应用的安全防护和逆向分析, 分享各种安全攻防手段、Hook 技术、ARM 汇编等 Android 相关的知识。 在 Kotlin 中,数据类(data class)自带一个

    2024年02月09日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包