I decided to do Java again, so I decided to write a gRPC server to update my knowledge of Java.
This article is wonderful, so I'm just streaming it, but since a lot of yak hair is being cut, I would like to include it.
The first thing I got stuck in was to create a very simple Hello World level console application with maven
. Simply use maven-archetype-quickstart
.
mvn archetype:generate
-DgroupId=com.simplearchitect \
-DartifactId=helloGRPC \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
proto file
Exactly Hello World level protobuf. Syntax
must be set to proto3
or the old version will be used. java_package
determines the package of the automatically generated class, so it might have been better to give it a more serious name. ʻOuter_classname` is the name of the auto-generated class that represents the concept of the protocol.
The protocol buffer below has a method called SayHello
and defines a simple service that returns HelloReply
when you send a HelloRequest
.
main/proto/helloworld.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Read this to get a better understanding of the proto
file.
It is necessary to automatically generate a class based on the proto
file. This requires maven
to be set to dependency
and plugin
.
Look at the top page of gRPC-Java --An RPC library and framework and set maven
.
You need to add ʻio.grpcfamily libraries and include
protobuf-maven-plugin and ʻos-maven-plugin
. By the way, ʻos-maven-plugin` is
os-maven-plugin is a Maven extension/plugin that generates various useful platform-dependent project properties normalized from ${os.name} and ${os.arch}.
And that. os-maven-plugin.
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.31.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.31.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.31.1</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
:
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.31.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
With this setting, mvn clean package
will automatically generate a class.
By the way, when creating a project in IntelliJ, it seems better to generate target
once and then execute it. If you leave the default, the target
directory will disappear. After creating target
, load the project into intelliJ and it will be set automatically. If not, you need to set the following settings File> Project Structure Module.
When loading into IntelliJ, if you do not right-click the project and select an additional Maven project, even if there is no error in maven
, the dependency on the screen cannot be resolved and an error occurs. It ends up.
Write a server with reference to the generated class. Allows this to be done from the Main program. All you have to do is start the server, configure it, and set the inherited classes.
package com.simplearchitect;
import java.io.IOException;
import java.util.logging.Logger;
import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.GreeterGrpc.GreeterImplBase;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.CallStreamObserver;
import static io.grpc.ServerBuilder.*;
public class SimpleServer {
Logger logger = Logger.getLogger(getClass().getName());
Server server;
public void start() throws IOException {
server = ServerBuilder
.forPort(8080)
.addService((BindableService) new SimpleHelloServiceImpl())
.build()
.start();
logger.info("start gRPC server.");
}
public void stop() {
if (server != null) {
server.shutdown();
logger.info("Shutting down gRPC server.");
}
}
public void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
public static class SimpleHelloServiceImpl extends GreeterImplBase {
Logger logger = Logger.getLogger(getClass().getName());
public void sayHello(HelloRequest request, CallStreamObserver<HelloReply> responseObserver) {
logger.info(String.format("request: name = %s", request.getName()));
HelloReply reply = HelloReply.newBuilder().setMessage("Hello, " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
abstract static class
Curiously, I have a new static class. What does this mean? The following class is the inheritance source class, but it is static abstract class
. This is actually not a static
class, but this class is an inner class and is marked with static
to indicate that it can be instantiated without instantiating the parent class of the inner class. So, in reality, it is a class that can be instantiated.
public static abstract class GreeterImplBase implements io.grpc.BindableService {
/**
* <pre>
* Sends a greeting
* </pre>
*/
public void sayHello(io.grpc.examples.helloworld.HelloRequest request,
io.grpc.stub.StreamObserver<io.grpc.examples.helloworld.HelloReply> responseObserver) {
asyncUnimplementedUnaryCall(getSayHelloMethod(), responseObserver);
}
@java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
.addMethod(
getSayHelloMethod(),
asyncUnaryCall(
new MethodHandlers<
io.grpc.examples.helloworld.HelloRequest,
io.grpc.examples.helloworld.HelloReply>(
this, METHODID_SAY_HELLO)))
.build();
}
}
Creating a jar file with mvn clean package
and executing it will result in an error. This is because Jar does not include the library. Let's add maven-assembly-plugin
. Now you can also specify mainClass
and it will create a library with the dependent jars.
`
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.simplearchitect.App</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>sample</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
The Assembly Plugin for Maven enables developers to combine project output into a single distributable archive that also contains dependencies, modules, site documentation, and other files.
Umm. Exactly what you were looking for.
PS > > java -jar .\target\helloGRPC-1.0-SNAPSHOT-jar-with-dependencies.jar
Aug 16, 2020 11:17:33 PM com.simplearchitect.SimpleServer start
INFO: start gRPC server.
> Enter stop.
I wonder if it works, but first of all, it was compiled, a jar with a library was created, and it worked. Next time, I will try to make a client and move it. I want to clearly understand the behavior of CallStreamObserver
.
Recommended Posts