• gRPC框架的简单使用


    01.概述

    进程间通信的演化过程

    进程间的通信:通常指的是一个应用实例调用另外一个应用实例所提供的服务,而这两个应用都运行在自己独立的进程中,通过网络彼此交换信息的过程。

    在这里插入图片描述
    进程间通信的演化过程:

    • 传统的RPC技术:JAVA远程方法调用(RMI),基于TCP通信实现远程调用,实现逻辑非常复杂,且只能规定在JAVA应用之间实现远程通信。

    • SOAP协议:简单对象访问协议,通过HTTP协议上封装XML格式的SOAP数据包,实现跨进程通信,是早期webService技术的底层实现,消息格式的复杂性与以及围绕SOAP所构建的各种规范的复杂性,妨碍了构建分布式应用程序的敏捷性,逐渐被REST架构风格的应用程序所替代。

    • RESTful架构风格:基于HTTP协议。

    • Google:gRPC框架,可以像调用本地方法一样调用远程方法。

    Google gRPC框架

    RPC(Remote Procedure Call)即远程过程调用:

    • 它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

    • RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层应用层,RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

    • RPC采用客户机/服务器模式,请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。

    RPC优势:

    • 提供高效的进程间通信,使用protobuf的二进制协议进行进程间的通信
    • 具有简单且定义良好的服务接口和模式(约定大于配置)
    • 属于强类型调用
    • 支持多语言
    • 支持双工通信

    RPC的缺点:

    • 不适合向外部提供服务
    • 巨大的服务定义变更起来比较复杂
    • gRPC生态系统相对较小

    gRPC传输格式protobuf:

    • protobuf(Google Protocol Buffers)是Google提供的一个高效数据交换的协议工具库,Protobuf有更高的转化效率,时间效率和空间效率,是JSON的3-5倍。
      在这里插入图片描述

    安装Protobuf环境和ProtobufIDEA插件

    proto文件编译器下载地址:https://github.com/protocolbuffers/protobuf/releases

    注意下载对应版本的编译器(windows,linux等),下载好之后解压,然后配置环境变量即可(bin目录)
    在这里插入图片描述

    查看能否运行,在cmd中输入命令:protoc --version 能打印出版本号即可

    在IDEA 插件中安装 Protobuf插件,安装这个插件之后会对proto文件有个语法检查和代码提示的功能

    02.原理

    GRPC底层原理

    在这里插入图片描述

    protobuf语法解析

    // proto版本
    syntax="proto3";
    // 是否生成多个类,true会生成多个类,false生成单个类
    option java_multiple_files=false;
    // 服务类所在的包
    option java_package="com.aismall.news.proto";
    //服务的名字:也就是服务的名字,一个服务中有多个接口
    option java_outer_classname = "NewsProto";
    // .proto包名
    package news;
    
    // service关键字,用于描述要生成的api接口是什么,类似于java的逻辑接口类
    // rpc 为关键字
    // rpc 方法(参数类型) returns (返回值类型){}
    
    service NewsService {
        rpc list(NewsRequest)
                returns (NewsResponse){}
    }
    
    /*
    	消息是rpc描述信息的基本单位,类似于java中的实体类
    	消息名字,对应于生成代码的类名
    	每个消息都对应生成的一个类,根据java_muitiple_files设置不同文件数量
    	option java_multiple_files=true; protobuf会给每个message生成一个java类
    	option java_multiple_files=false; protobuf会生成一个大类,消息为该类的子类,都在一个java大类中
    */
    
    /*
    	字段定义方式:
    		类型 名称 =索引值(id)
    		每个字段都要定义一个唯一的索引值,这些数字用来在消息二进制时,用来识别字段
    		一旦开始使用就不能再更改,标识号从1开始
    		可以为将来需要使用的标识号预留标识符
    */
    message NewsRequest {
        string data = 1;
    }
    
    message NewsResponse {
    	// repeated说明是一个集合(数组),数组的每一个对象都是news
        repeated News news = 1;
    }
    message News {
        int32 id = 1;
        string title = 2;
        string content=3;
        int64 createTime=4;
    }
    
    /*
    	生成文件介绍:
    		消息名orBuilder:消息类于构造器接口
    		消息名:消息的具体实现
    	protobuf还可以实现类型的嵌套,嵌套之后必须要声明这个message才可以
    */
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    注意:

    • proto文件:可以生成不同语言的代码,通过不同的指令生成不同的语言代码,如java,go等。

    • poto文件中的message一旦定义好编号,尽量不要修改。

    生成代码解析

    在这里插入图片描述

    03.案例实战演示

    在这里插入图片描述
    客户端和服务端进行通信的依据就是基于相同的proto文件生成的代码,两种方式:

    • 方式一:server端和client端使用相同的proto文件,生成相同的代码。
    • 方式二:使用proto生成代码之后,将相应的代码打成jar包,然后上传到自己的中央仓库,然后server端和client端都引用这个jar包。

    注意:

    • springoot版本:2.4.1

    RPC服务端搭建

    步骤:

    • 添加gRPC依赖坐标,引入protobuf-maven-plugin插件
    • 编写proto文件
    • 实现服务端业务逻辑
    • 服务端开发

    1、新建一个maven项目,引入如下依赖以及插件

    <dependencies>
        <dependency>
            <groupId>com.google.protobufgroupId>
            <artifactId>protobuf-javaartifactId>
            <version>3.21.2version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-netty-shadedartifactId>
            <version>1.42.0version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-protobufartifactId>
            <version>1.42.0version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-stubartifactId>
            <version>1.42.0version>
        dependency>
        <dependency>
            <groupId>org.apache.tomcatgroupId>
            <artifactId>annotations-apiartifactId>
            <version>6.0.53version>
            <scope>providedscope>
        dependency>
    dependencies>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.mavengroupId>
                <artifactId>os-maven-pluginartifactId>
                <version>1.6.2version>
            extension>
        extensions>
        <plugins>
            <plugin>
                
                <groupId>org.xolstice.maven.pluginsgroupId>
                <artifactId>protobuf-maven-pluginartifactId>
                <version>0.6.1version>
                <configuration>
                    
                    <protocArtifact>com.google.protobuf:protoc:3.21.2:exe:${os.detected.classifier}protocArtifact>
                    <pluginId>grpc-javapluginId>
                    
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}pluginArtifact>
                configuration>
                <executions>
                    <execution>
                        <goals>
                            
                            <goal>compilegoal>
                            
                            <goal>compile-customgoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2、在main目录下新建一个proto文件,用于存放拓展名proto结尾的文件(news.proto)。

    syntax="proto3";
    option java_multiple_files=false;
    option java_package="com.aismall.news.proto";
    option java_outer_classname = "NewsProto";
    package news;
    service NewsService{
        rpc list(NewsRequest) returns (NewsResponse){}
    }
    message NewsRequest{
        string date=1;
    }
    message NewsResponse{
        repeated News news = 1;
    }
    message News{
        int32 id = 1;
        string title = 2;
        string content=3;
        int64 createTime=4;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3、使用插件生成消息代码GRPC通信文件

    • Maven——>Plugins—>protobuf——>compile:生成消息代码
    • Maven——>Plugins—>protobuf——>compile-custom:生成GRPC通信文件

    4、移动生成的文件:生成的文件会在target/generated-sources/protobuf/grpc-java目录target/generated-sources/protobuf/java目录下面,将生成文件移动到源代码同级目录下即可。

    5、编写业务类:继承NewsServiceGrpc.NewsServiceImplBase类,并实现里面的方法,在方法里重写业务逻辑。

    public class NewsService extends NewsServiceGrpc.NewsServiceImplBase {
        //注意:入参为方法里面第一个参数,出参为方法里面的第二个参数
        @Override
        public void list(NewsProto.NewsRequest request, StreamObserver<NewsProto.NewsResponse> responseObserver) {
            // 获取入参的data属性
            String date = request.getDate();
            // 反参对象
            NewsProto.NewsResponse newsList = null;
            try {
                // 反参的构建器
                NewsProto.NewsResponse.Builder newsListBuilder = NewsProto.NewsResponse.newBuilder();
                for ( int i = 1;i<=25;i++ ){
                    // 构建反参中的存储的实体类
                    NewsProto.News news = NewsProto.News.newBuilder().setId(i)
                            .setContent(date + "新闻内容" + i)
                            .setTitle("新闻标题" + i)
                            .setCreateTime(new Date().getTime())
                            .build();
                    // 将构建好的实体类存入反参的构建器中
                    newsListBuilder.addNews(news);
                }
                // 调用build()方法完成反参的构建
                newsList = newsListBuilder.build();
            } catch (Exception e) {
                responseObserver.onError(e);
            }finally {
                // 实用观察者模式,将参数返回
                responseObserver.onNext(newsList);
            }
            // 关闭
            responseObserver.onCompleted();
        }
    }
    
    • 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

    6、修改启动类:

    public class GrpcNewsServer {
    	// 定义一个端口
        public static final int port = 7520;
        public static void main(String[] args) throws InterruptedException, IOException {
        	// 启动grpc服务
            io.grpc.Server server = ServerBuilder.forPort(port).addService(new NewsService())
                    .build().start();
            System.out.println(String.format("GRPC 服务启动,端口号:%d", port));
            server.awaitTermination();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    RPC客户端

    1 、2、3、4步骤如法炮制(参考:server端)

    5、修改主启动类:在主启动类中调用server端提供的服务。

    /*
    * 测试 NewsService接口中的list服务
    * */
    public class GrpcNewsClient {
        // 访问server的url和端口号
        private static final String host="localhost";
        private static final int serverPort=7520;
        public static void main(String[] args) {
            //建立一个传输文本的通道
            ManagedChannel channel= ManagedChannelBuilder.forAddress(host,serverPort).usePlaintext()
                    .build();
            // 创建一个传输通道,使用阻塞模式
            NewsServiceGrpc.NewsServiceBlockingStub blockingStub=NewsServiceGrpc.newBlockingStub(channel);
            //创建一个入参类
            NewsProto.NewsRequest request= NewsProto.NewsRequest.newBuilder().setData("20220709").build();
            // 调用NewService接口中的list服务:调用方式类似于调用方法一样。
            // 调用之后,会给我们返回一个出参类型的值:NewsResponse实例,该实例在服务端创建,通过上面定义的通信方式传输过来
            NewsProto.NewsResponse response=blockingStub.list(request);
            //获取出参实例中的参数
            List<NewsProto.News> newsList=response.getNewsList();
            for (NewsProto.News news:newsList) {
                System.out.println(news);
            }
            //关闭传输通道
            channel.shutdown();
        }
    }
    
    • 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

    小结

    通过上面的例子我们可以看出,rpc服务之间的调用,就好像调用自己本地的方法一样。

    本次演示,server端和client端使用相同的proto文件,生成相同的代码。

    后面介绍springboot整合grpc框架的时候采用,使用proto生成代码之后,将相应的代码打成jar包,然后上传到自己的中央仓库,然后server端和client端都引用这个jar包。

    04.Springboot整合gPRC

    grpc-server-spring-boot-starter/grpc-client-spring-boot-starter是第三方提供的Springboot整合gRPC的整合包,基于Springboot自动装配和声明式特性,整体简化了gRPC在Springboot的开发过程。

    提前准备

    新建一个项目maven项目,用于将proto文件生成代码打成jar包,然后上传到自己的本地仓库。

    1、新建名为news的Maven工程,引入如下依赖。

    <dependencies>
        <dependency>
            <groupId>com.google.protobufgroupId>
            <artifactId>protobuf-javaartifactId>
            <version>3.21.2version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-netty-shadedartifactId>
            <version>1.42.0version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-protobufartifactId>
            <version>1.42.0version>
        dependency>
        
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-stubartifactId>
            <version>1.42.0version>
        dependency>
        <dependency>
            <groupId>org.apache.tomcatgroupId>
            <artifactId>annotations-apiartifactId>
            <version>6.0.53version>
            <scope>providedscope>
        dependency>
    dependencies>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.mavengroupId>
                <artifactId>os-maven-pluginartifactId>
                <version>1.6.2version>
            extension>
        extensions>
        <plugins>
            <plugin>
                
                <groupId>org.xolstice.maven.pluginsgroupId>
                <artifactId>protobuf-maven-pluginartifactId>
                <version>0.6.1version>
                <configuration>
                    
                    <protocArtifact>com.google.protobuf:protoc:3.21.2:exe:${os.detected.classifier}protocArtifact>
                    <pluginId>grpc-javapluginId>
                    
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}pluginArtifact>
                configuration>
                <executions>
                    <execution>
                        <goals>
                            
                            <goal>compilegoal>
                            
                            <goal>compile-customgoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    2、在main目录下新建一个proto文件夹,用于存放拓展名proto结尾的文件(news.proto)。

    syntax="proto3";
    option java_multiple_files=false;
    option java_package="com.aismall.news.proto";
    option java_outer_classname = "NewsProto";
    package news;
    service NewsService{
        rpc list(NewsRequest) returns (NewsResponse){}
    }
    message NewsRequest{
        string date=1;
    }
    message NewsResponse{
        repeated News news = 1;
    }
    message News{
        int32 id = 1;
        string title = 2;
        string content=3;
        int64 createTime=4;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3、使用插件生成消息代码GRPC通信文件

    • Maven——>Plugins—>protobuf——>compile:生成消息代码
    • Maven——>Plugins—>protobuf——>compile-custom:生成GRPC通信文件

    4、移动生成的文件:生成的文件会在target/generated-sources/protobuf/grpc-java目录target/generated-sources/protobuf/java目录下面,将生成文件移动到源代码同级目录下即可。

    5、在POM文件里把插件注释掉,要不然在第六步会报错。

    6、在maven插件中的Lifecyle中: 先双击clean、在双击install,就可以把我们的news项目上传到本地仓库了。

    注意: 依赖的坐标
    在这里插入图片描述

    server

    1、新建一个Springboot项目,Springboot版本为2.4.1。

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    
        
        <dependency>
            <groupId>net.devhgroupId>
            <artifactId>grpc-server-spring-boot-starterartifactId>
            <version>2.13.0.RELEASEversion>
        dependency>
    
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-allartifactId>
            <version>1.42.0version>
        dependency>
         
        <dependency>
            <groupId>org.aismallgroupId>
            <artifactId>newsartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
    dependencies>
    
    • 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

    2、编写业务类,继承NewsServiceGrpc.NewsServiceImplBase类,并实现里面的方法

    // 使用注解标注这是一个Grpc的服务:标识接口
    //springboot扫描的时候,会认为这个类是grpc的实现类
    @GrpcService
    public class NewsService extends NewsServiceGrpc.NewsServiceImplBase {
        //注意:入参为方法里面第一个参数,出参为方法里面的第二个参数
        @Override
        public void list(NewsProto.NewsRequest request, StreamObserver<NewsProto.NewsResponse> responseObserver) {
            // 获取入参的data属性
            String date = request.getDate();
            // 反参对象
            NewsProto.NewsResponse newsList = null;
            try {
                // 反参的构建器
                NewsProto.NewsResponse.Builder newsListBuilder = NewsProto.NewsResponse.newBuilder();
                for ( int i = 1;i<=25;i++ ){
                    // 构建反参中的存储的实体类
                    NewsProto.News news = NewsProto.News.newBuilder().setId(i)
                            .setContent(date + "新闻内容" + i)
                            .setTitle("新闻标题" + i)
                            .setCreateTime(new Date().getTime())
                            .build();
                    // 将构建好的实体类存入反参的构建器中
                    newsListBuilder.addNews(news);
                }
                // 调用build()方法完成反参的构建
                newsList = newsListBuilder.build();
            } catch (Exception e) {
                responseObserver.onError(e);
            }finally {
                // 实用观察者模式,将参数返回
                responseObserver.onNext(newsList);
            }
            // 关闭
            responseObserver.onCompleted();
        }
    }
    
    • 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

    3、修改配置文件

    # 应用名称
    spring.application.name=springboot-grpc-server
    # web服务:内置tomcat对外提供的端口号
    server.port = 8725
    # grpc服务:grpc服务之间通信的端口号
    grpc.server.port = 7725
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、启动服务等待客户端的调用。

    client

    1、新建一个Springboot项目,Springboot版本为2.4.1。

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    
        
        <dependency>
            <groupId>net.devhgroupId>
            <artifactId>grpc-client-spring-boot-starterartifactId>
            <version>2.13.0.RELEASEversion>
        dependency>
    
        <dependency>
            <groupId>io.grpcgroupId>
            <artifactId>grpc-allartifactId>
            <version>1.42.0version>
        dependency>
    
        <dependency>
            <groupId>org.aismallgroupId>
            <artifactId>newsartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
    dependencies>
    
    • 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

    2、编controller类,继承NewsServiceGrpc.NewsServiceImplBase类,并实现里面的方法。

    //restful风格的控制器
    @RestController
    public class NewsController {
        //指向配置文件的 grpc-server 配置
        @GrpcClient("grpc-server")
        private NewsServiceGrpc.NewsServiceBlockingStub newsServiceBlockingStub;
    
        //访问链接地址:localhost:8726/news?date=20220725
        @GetMapping("news")
        public String news(String date) {
            System.out.println("==================");
            NewsProto.NewsResponse newsResponse = newsServiceBlockingStub.list(NewsProto.NewsRequest.newBuilder().setDate(date).build());
            return newsResponse.getNewsList().toString();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3、修改配置文件

    # 应用名称
    spring.application.name=springboot-grpc-client
    # web服务 :内置tomcat对外提供的端口号
    server.port = 8726
    # 定义客户端访问的grpc服务地址和端口号
    grpc.client.grpc-server.address= static://localhost:7725
    # 文本响应
    grpc.client.grpc-server.negotiation-type: plaintext
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、启动服务,使用浏览器访问:localhost:8726/news?date=20220725

    05.总结

    代码地址:https://gitee.com/aismall/mystudym

  • 相关阅读:
    猿创征文|Axios的介绍与作用 - 大白话
    JS深入理解立即执行函数,js匿名函数()
    概率论的学习和整理13--方差和协方差(未完成)
    pandas教程:Essential Functionality 索引 过滤 映射 排序
    【算法】Convert to Base -2 负二进制转换
    SOA中间件DDS(数据分发服务-Data Distribution Service)
    热心肠行为?苹果“偷偷“给应用买广告
    PASS计算样本量(1)---完全随机设计时两样本率比较
    Go语言,一段奇怪的代码
    【PAT甲级 - C++题解】1072 Gas Station
  • 原文地址:https://blog.csdn.net/weixin_45583303/article/details/125646495