Welcome to my GitHub

https://github.com/zq2599/blog_demos

Content: Classification and summary of all original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc.;

About the "java version of gRPC combat" series

  • "Java version of gRPC actual combat" is Xinchen's original gRPC development notes for java programmers, with readers to learn and master various knowledge points of gRPC through actual combat;

"Java version of gRPC combat" full series of links

  1. Generate code with proto
  2. service release and call
  3. server stream
  4. client stream
  5. two-way flow
  6. client dynamically obtains the server address
  7. based on eureka registration discovery

About gRPC

  1. gRPC is a high-performance, open source and general-purpose RPC framework, designed for mobile and HTTP/2. Currently available in C, Java and Go language versions: grpc, grpc-java, grpc-go. The C version supports C, C++, Node.js, Python, Ruby, Objective-C, PHP and C#.
  2. gRPC is designed based on the HTTP/2 standard, bringing features such as bidirectional streaming, flow control, header compression, and multiplexing requests on a single TCP connection. These features make it perform better on mobile devices, save power and save space.
  3. Each process can call each other through gRPC, as shown below:

在这里插入图片描述

Core technologies

  • In order to publish gRPC services in java, I use the open source library <font color="blue">net.devh:grpc-server-spring-boot-starter</font>
  • When calling other gRPC services, use <font color="blue">net.devh:grpc-client-spring-boot-starter</font>
  • Thank you Michael, the author of the open source library. Your wisdom has simplified the gRPC development work of java programmers. Project address: https://github.com/yidongnan/grpc-spring-boot-starter

Overview of this article

As the beginning of a series of articles, the things to do in this article are as follows:

  1. Clearly rely on libraries and development environment
  2. Create a new parent project <font color="blue">grpc-tutorials</font>, and all the source code of the "java version of gRPC actual combat" series will be in this project
  3. Automatically generate java code with proto file in actual combat

Clearly rely on libraries and development environment

The dependent libraries and development environment involved in the entire series of articles are as follows:

  1. JDK:1.8.0_281
  2. gradle:6.7.1
  3. springboot:2.3.8.RELEASE
  4. grpc:1.35.0
  5. protobuf:3.14.0
  6. grpc-server-spring-boot-starter:2.11.0.RELEASE
  7. grpc-client-spring-boot-starter:2.11.0.RELEASE
  8. Operating System: win10 Professional Edition
  9. IDEA:2021.1 (Ultimate Edition)

Source download

namelinkRemarks
Project homepagehttps://github.com/zq2599/blog_demosThe project's homepage on GitHub
git warehouse address (https)https://github.com/zq2599/blog_demos.gitThe warehouse address of the source code of the project, https protocol
git warehouse address (ssh)git@github.com:zq2599/blog_demos.gitThe warehouse address of the source code of the project, ssh protocol
  • There are multiple folders in this git project. The source code of the "java version of gRPC combat" series is under the <font color="blue">grpc-tutorials</font> folder, as shown in the red box below:

在这里插入图片描述

Created the parent project of the "java version of gRPC actual combat" series

  • Create a new gradle project named <font color="blue">grpc-tutorials</font>. The aforementioned libraries and their versions are handled in this project. The content of build.gradle is as follows:
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter

buildscript {
    repositories {
        maven {
            url 'https://plugins.gradle.org/m2/'
        }
        // 如果有私服就在此配置,如果没有请注释掉
        maven {
            url 'http://192.168.50.43:8081/repository/aliyun-proxy/'
        }
        // 阿里云
        maven {
            url 'http://maven.aliyun.com/nexus/content/groups/public/'
        }

        mavenCentral()
    }
    ext {
        // 项目版本
        projectVersion = '1.0-SNAPSHOT'

        // 依赖库的版本
        grpcSpringBootStarterVersion = '2.11.0.RELEASE'

        // grpc版本 https://github.com/grpc/grpc-java/releases
        grpcVersion = '1.35.0'
        // protobuf版本 https://github.com/protocolbuffers/protobuf/releases
        protobufVersion = '3.14.0'
        // protobuf的gradle插件版本
        protobufGradlePluginVersion = '0.8.12'

        // sprignboot版本 https://github.com/spring-projects/spring-boot/releases
        springBootVersion = '2.3.8.RELEASE'
        // springcloud版本 https://github.com/spring-cloud/spring-cloud-release/releases
        springCloudVersion = 'Hoxton.SR9'
        // nacos版本 https://github.com/alibaba/spring-cloud-alibaba/releases
        springCloudAlibabaNacosVersion = '2.2.3.RELEASE'
        // security版本 https://github.com/spring-projects/spring-security-oauth/releases
        springSecurityOAuthVersion = '2.5.0.RELEASE'
    }
}

plugins {
    id 'java'
    id 'java-library'
    id 'org.springframework.boot' version "${springBootVersion}" apply false
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'net.nemerosa.versioning' version '2.14.0'
    id 'com.google.protobuf' version '0.8.14'
    id 'io.franzbecker.gradle-lombok' version '4.0.0' apply false
    id 'com.github.ben-manes.versions' version '0.36.0' // gradle dependencyUpdates
}

// If you attempt to build without the `--scan` parameter in `gradle 6.0+` it will cause a build error that it can't find
// a buildScan property to change. This avoids that problem.
if (hasProperty('buildScan')) {
    buildScan {
        termsOfServiceUrl = 'https://gradle.com/terms-of-service'
        termsOfServiceAgree = 'yes'
    }
}

wrapper {
    gradleVersion = '6.7.1'
}

def buildTimeAndDate = OffsetDateTime.now()

ext {
    // 构建时取得当前日期和时间
    buildDate = DateTimeFormatter.ISO_LOCAL_DATE.format(buildTimeAndDate)
    buildTime = DateTimeFormatter.ofPattern('HH:mm:ss.SSSZ').format(buildTimeAndDate)
    buildRevision = versioning.info.commit
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'eclipse'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'io.franzbecker.gradle-lombok'

    compileJava {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
        options.encoding = 'UTF-8'
    }

    compileJava.options*.compilerArgs = [
            '-Xlint:all', '-Xlint:-processing'
    ]

    // Copy LICENSE
    tasks.withType(Jar) {
        from(project.rootDir) {
            include 'LICENSE'
            into 'META-INF'
        }
    }

    // 写入到MANIFEST.MF中的内容
    jar {
        manifest {
            attributes(
                    'Created-By': "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})".toString(),
                    'Built-By': 'travis',
                    'Build-Date': buildDate,
                    'Build-Time': buildTime,
                    'Built-OS': "${System.properties['os.name']}",
                    'Build-Revision': buildRevision,
                    'Specification-Title': project.name,
                    'Specification-Version': projectVersion,
                    'Specification-Vendor': 'Will Zhao',
                    'Implementation-Title': project.name,
                    'Implementation-Version': projectVersion,
                    'Implementation-Vendor': 'Will Zhao'
            )
        }
    }

    repositories {
        mavenCentral()

        // 如果有私服就在此配置,如果没有请注释掉
        maven {
            url 'http://192.168.50.43:8081/repository/aliyun-proxy/'
        }

        // 阿里云
        maven {
            url 'http://maven.aliyun.com/nexus/content/groups/public/'
        }

        jcenter()
    }

    buildscript {
        repositories {
            maven { url 'https://plugins.gradle.org/m2/' }
        }
    }
}

allprojects { project ->
    buildscript {
        dependencyManagement {
            imports {
                mavenBom "org.springframework.boot:spring-boot-starter-parent:${springBootVersion}"
                mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
                mavenBom "com.google.protobuf:protobuf-bom:${protobufVersion}"
                mavenBom "io.grpc:grpc-bom:${grpcVersion}"
                mavenBom "org.junit:junit-bom:5.7.0"
            }

            dependencies {
                dependency 'org.projectlombok:lombok:1.16.16'
                dependency 'org.apache.commons:commons-lang3:3.11'
                dependency 'commons-collections:commons-collections:3.2.2'
                dependency "net.devh:grpc-server-spring-boot-starter:${grpcSpringBootStarterVersion}"
                dependency "net.devh:grpc-client-spring-boot-starter:${grpcSpringBootStarterVersion}"
            }
        }

        ext {
            micrometerVersion = dependencyManagement.importedProperties['micrometer.version']
            springFrameworkVersion = dependencyManagement.importedProperties['spring-framework.version']
            springSecurityVersion = dependencyManagement.importedProperties['spring-security.version']
            springCloudCommonsVersion = dependencyManagement.importedProperties['spring-cloud-commons.version']
        }
    }
}

group = 'com.bolingcavalry'
version = projectVersion
  • The parent project used in the entire series has been completed, and then you can start coding;

Automatically generate java code with proto file in actual combat

  • The gRPC service can be written in different languages. The key is that the proto file that defines the service can be generated into codes in various languages. Java is no exception, let’s experience it together;
  • Create a new module under the parent project <font color="blue">grpc-tutorials</font>, named <font color="blue">grpc-lib</font>, and its build.gradle content is as follows, it can be seen that the main ones are The protobuf plug-in is configured, and how the generated java code can be added to the source path by the IDE tool:
// 根据proto生成java代码的gradle插件
plugins {
    id 'com.google.protobuf'
}

dependencies {
    implementation 'io.grpc:grpc-netty-shaded'
    implementation 'io.grpc:grpc-protobuf'
    implementation 'io.grpc:grpc-stub'
    if (JavaVersion.current().isJava9Compatible()) {
        // Workaround for @javax.annotation.Generated
        // see: https://github.com/grpc/grpc-java/issues/3633
        implementation 'jakarta.annotation:jakarta.annotation-api'
    }
}


protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:${protobufVersion}"
    }
    // 自动生成的代码放在这里
    generatedFilesBaseDir = "$projectDir/src/generated"
    clean {
        delete generatedFilesBaseDir
    }
    // 生成java代码的插件
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
    }
}

// 对于eclipse,通过以下脚本可以将生成的代码加入source路径中,编译时会被用到
eclipse {
    classpath {
        file.beforeMerged { cp ->
            def generatedGrpcFolder = new org.gradle.plugins.ide.eclipse.model.SourceFolder('src/generated/main/grpc', null);
            generatedGrpcFolder.entryAttributes['ignore_optional_problems'] = 'true';
            cp.entries.add( generatedGrpcFolder );
            def generatedJavaFolder = new org.gradle.plugins.ide.eclipse.model.SourceFolder('src/generated/main/java', null);
            generatedJavaFolder.entryAttributes['ignore_optional_problems'] = 'true';
            cp.entries.add( generatedJavaFolder );
        }
    }
}

// 对于idea,通过以下脚本可以将生成的代码加入source路径中,编译时会被用到
idea {
    module {
        sourceDirs += file('src/generated/main/java')
        sourceDirs += file('src/generated/main/grpc')
        generatedSourceDirs += file('src/generated/main/java')
        generatedSourceDirs += file('src/generated/main/grpc')
    }
}
  • Add a new file named <font color="red">helloworld.proto</font> in the <font color="blue">src/main/proto</font> directory of the grpc-lib module, which defines A gRPC service contains an interface, and the definition of the input parameters and return results of this interface:
syntax = "proto3";

option java_multiple_files = true;
// 生成java代码的package
option java_package = "com.bolingcavalry.grpctutorials.lib";
option java_outer_classname = "HelloWorldProto";

// gRPC服务
service Simple {
    // 接口定义
    rpc SayHello (HelloRequest) returns (HelloReply) {
    }
}

// 入参的数据结构
message HelloRequest {
    string name = 1;
}

// 返回结果的数据结构
message HelloReply {
    string message = 1;
}
  • The proto file is ready. Next, we need to generate java code based on this file. In the <font color="red">grpc-tutorials</font> directory, execute the command <font color="blue">gradle grpc-lib: generateProto</font>, you can generate java code based on the helloworld.proto file. After successful execution, the content in the red box below will be generated. These are the java codes:

在这里插入图片描述

  • This article only talks about how to generate the above code. As for the purpose of the code, I will leave it to the next article. I will just mention it briefly. There is an abstract class SimpleImplBase in SimpleGrpc, which needs to be inherited when making gRPC services. In addition, if you To remotely call the sayHello interface of gRPC, the SimpleStub class in the SimpleGrpc class will be used, and the rest of HelloReply and HelloRequest are the input parameters and return data structure definitions;
  • At this point, the preparations for the actual combat of the java version of gRPC have been completed, and the method of generating java code based on the proto file has also been mastered. In the following chapters, let's try to publish and call the service together;

You are not alone, Xinchen and original are with you all the way

  1. Java series
  2. Spring series
  3. Docker series
  4. kubernetes series
  5. database + middleware series
  6. DevOps series

Welcome to pay attention to the public account: programmer Xin Chen

Search "Programmer Xin Chen" on WeChat, I am Xin Chen, and I look forward to traveling the Java world with you...
https://github.com/zq2599/blog_demos

程序员欣宸
147 声望24 粉丝

热爱Java和Docker