About the "java version of gRPC actual combat" series
- The java version of gRPC actual combat is a gRPC development note for java programmers originally written by Xinchen. We will learn and master various knowledge points of gRPC through actual combat with readers;
Links to the full series of "java version gRPC actual combat"
- Generate code with proto
- Service publishing and invocation
- Server stream
- Client stream
- Bidirectional flow
- The client dynamically obtains the server address
- Registration discovery based on eureka
About gRPC
- gRPC is a high-performance, open source and general RPC framework designed for mobile and HTTP/2. At present, C, Java and Go language versions are available: gRPC, gRPC Java and gRPC Go. Among them, C version supports C, C++, Node.js, Python, Ruby, Objective-C, PHP and c# support
- gRPC is designed based on the HTTP/2 standard and brings features such as bidirectional flow, flow control, header compression, multiple multiplexing requests on a single TCP connection and so on. These features make it perform better on mobile devices, save power and save space.
- Each process can call each other through gRPC, as shown in the following figure:

core technology
- In order to publish gRPC services in java, I use the open source library net. Devh: gRPC server spring boot starter
- Net. Devh: gRPC client spring boot starter is used when calling other gRPC services
- Thank Michael Dashen, the author of the open source library, for your wisdom in simplifying 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 this series of articles, the following things should be done in this article:
- Explicit dependency library and development environment
- Create a new parent project gRPC tutorials. In the future, all the source codes of the java version gRPC actual combat series will be in this project
- Automatic generation of java code with proto file in actual combat
Explicit dependency library and development environment
The dependency libraries and development environments covered in the whole series of articles are as follows:
- JDK: 1.8.0_281
- gradle: 6.7.1
- springboot: 2.3.8.RELEASE
- grpc: 1.35.0
- protobuf: 3.14.0
- grpc-server-spring-boot-starter: 2.11.0.RELEASE
- grpc-client-spring-boot-starter: 2.11.0.RELEASE
- Operating system: win10 Professional Edition
- IDEA: 2021.1 (Ultimate Edition)
Source download
- The complete source code in this actual combat can be downloaded from GitHub. The address and link information are shown in the table below( https://github.com/zq2599/blog_demos):
name | link | remarks |
---|---|---|
Project Home | https://github.com/zq2599/blog_demos | The project is on the GitHub home page |
git warehouse address (https) | https://github.com/zq2599/blog_demos.git | The warehouse address of the source code of the project, https protocol |
git warehouse address (ssh) | git@github.com:zq2599/blog_demos.git | The project source code warehouse address, ssh protocol |
- There are multiple folders in the git project. The source code of the gRPC practical combat series for java is in the gRPC tutorials folder, as shown in the red box below:

Create the parent project of gRPC Practice Series in java
- Create a new gradle project named grpc tutorials. The previously mentioned 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/' } // If there is a private server, configure it here. If not, please comment it out maven { url 'http://192.168.50.43:8081/repository/aliyun-proxy/' } // Alibaba cloud maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } mavenCentral() } ext { // Project version projectVersion = '1.0-SNAPSHOT' // Version of dependent Library grpcSpringBootStarterVersion = '2.11.0.RELEASE' // Grpc version https://github.com/grpc/grpc-java/releases grpcVersion = '1.35.0' // Protobuf version https://github.com/protocolbuffers/protobuf/releases protobufVersion = '3.14.0' // gradle plug-in version of protobuf protobufGradlePluginVersion = '0.8.12' // sprignboot version https://github.com/spring-projects/spring-boot/releases springBootVersion = '2.3.8.RELEASE' // Spring cloud version https://github.com/spring-cloud/spring-cloud-release/releases springCloudVersion = 'Hoxton.SR9' // nacos version https://github.com/alibaba/spring-cloud-alibaba/releases springCloudAlibabaNacosVersion = '2.2.3.RELEASE' // Security version 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 { // Get the current date and time at build time 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' } } // Content written to 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() // If there is a private server, configure it here. If not, please comment it out maven { url 'http://192.168.50.43:8081/repository/aliyun-proxy/' } // Alibaba cloud 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 whole series has been completed, and then you can start coding;
Automatic generation of java code with proto file in actual combat
- gRPC services can be written in different languages. The key is that the proto file defining the service can be generated into codes in various languages, including java. Let's experience it together next;
- Create a new module named grpc lib under the parent project grpc tutorials. The content of its build.gradle is as follows. It can be seen that the protobuf plug-in is configured and how the generated java code can be added to the source path by the IDE tool:
// gradle plug-in for generating java code according to proto 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}" } // The automatically generated code is here generatedFilesBaseDir = "$projectDir/src/generated" clean { delete generatedFilesBaseDir } // Plug in for generating java code plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java' } } generateProtoTasks { all()*.plugins { grpc {} } } } // For eclipse, the generated code can be added to the source path through the following script, which will be used during compilation 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 ); } } } // For idea, the generated code can be added to the source path through the following script, which will be used during compilation 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') } }
- A new file named helloworld.proto is added in the src/main/proto directory of gRPC lib module, which defines a gRPC service, which contains an interface, and the definition of the input participation and return result of this interface:
syntax = "proto3"; option java_multiple_files = true; // package for generating java code option java_package = "com.bolingcavalry.grpctutorials.lib"; option java_outer_classname = "HelloWorldProto"; // gRPC service service Simple { // Interface definition rpc SayHello (HelloRequest) returns (HelloReply) { } } // Data structure of input parameter message HelloRequest { string name = 1; } // Return the data structure of the result message HelloReply { string message = 1; }
- The proto file is ready. Next, generate java code according to this file. Execute the command gradle grpc lib: generateproto in the grpc tutorials directory to generate java code according to the helloworld.proto file. After successful execution, the contents in the red box below will be generated. These are Java Codes:

- This article only talks about how to generate the above codes. The purpose of these codes will be left to the next article. Here, it is only briefly mentioned that there is an abstract class SimpleImplBase in SimpleGrpc, which needs to be inherited when making gRPC services. In addition, if you want to remotely call the sayHello interface of gRPC, you will use the simplestab class in SimpleGrpc class, and the rest hellopreply HelloRequest these are data structure definitions returned by input participants;
- So far, the preparations for the actual combat of the Java version of gRPC have been completed, and the method of generating java code according to the proto file has been mastered. In the next chapter, let's try to publish and call the service together;