java version of gRPC practice 2: service publishing and calling

Links to the full series of "java version gRPC actual combat"

  1. Generate code with proto
  2. Service publishing and invocation
  3. Server stream
  4. Client stream
  5. Bidirectional flow
  6. The client dynamically obtains the server address
  7. Registration discovery based on eureka

Overview of this article

  • This article is the second in the "java version of gRPC actual combat" series Generating code with proto Prepare the java code corresponding to the parent project, dependency library version and helloworld.proto. Today's task is to develop and call the actual gRPC service. The implementation effect is as follows:
  • The specific operations of this chapter are as follows:
  1. Develop a springboot application named local server to provide gRPC service defined in helloworld.proto;
  2. Develop a springboot application named local client and call the gRPP service provided by local server;
  3. Verify whether gRPC service can be called normally;

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:
  • There are multiple directories under the grpc tutorials folder. The corresponding codes of this article are in local server and local client, as shown in the red box below:

Develop gRPC server

  • The first thing to develop is the gRPC server. Review the services and interfaces defined in helloworld.proto above. As shown below, the service named Simple provides an external SayHello interface. This is our next task. Create a springboot application that provides the SayHello interface to other applications for remote calls in the form of gRPC:
service Simple {
    // Interface definition
    rpc SayHello (HelloRequest) returns (HelloReply) {
    }
}
  • Developing a common gRPC server application based on the springboot framework requires five steps, as shown in the figure below. Next, we will develop it according to the sequence number in the figure below:
  • First, create a new module named local server under the parent project grpc tutorials. The content of build.gradle is as follows:
// Using the springboot plug-in
plugins {
    id 'org.springframework.boot'
}

dependencies {
    implementation 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter'
    // As a gRPC service provider, you need to use this library
    implementation 'net.devh:grpc-server-spring-boot-starter'
    // Projects that rely on automatic source code generation
    implementation project(':grpc-lib')
}
  • This is a springboot application. The configuration file is as follows:
spring:
  application:
    name: local-server
# For the configuration related to gRPC, only the service port number needs to be configured here
grpc:
  server:
    port: 9898
  • Create a new interception class LogGrpcInterceptor.java. This class will execute first after the gRPC request arrives. Here, print the method name in the log. You can handle the request response in more detail:
package com.bolingcavalry.grpctutorials;

import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogGrpcInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
                                                                 ServerCallHandler<ReqT, RespT> serverCallHandler) {
        log.info(serverCall.getMethodDescriptor().getFullMethodName());
        return serverCallHandler.startCall(serverCall, metadata);
    }
}
  • In order for the LogGrpcInterceptor to be executed when gRPC requests arrive, you need to configure it accordingly, as shown below. You can add notes to the configuration of ordinary bean s:
package com.bolingcavalry.grpctutorials;

import io.grpc.ServerInterceptor;
import net.devh.boot.grpc.server.interceptor.GrpcGlobalServerInterceptor;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class GlobalInterceptorConfiguration {
    @GrpcGlobalServerInterceptor
    ServerInterceptor logServerInterceptor() {
        return new LogGrpcInterceptor();
    }
}
  • The application startup class is simple:
package com.bolingcavalry.grpctutorials;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LocalServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(LocalServerApplication.class, args);
    }
}
  • Next is the most important service class. gRPC service is exposed here. The complete code is as follows. Several points to note will be mentioned later:
package com.bolingcavalry.grpctutorials;

import com.bolingcavalry.grpctutorials.lib.HelloReply;
import com.bolingcavalry.grpctutorials.lib.SimpleGrpc;
import net.devh.boot.grpc.server.service.GrpcService;
import java.util.Date;

@GrpcService
public class GrpcServerService extends SimpleGrpc.SimpleImplBase {

    @Override
    public void sayHello(com.bolingcavalry.grpctutorials.lib.HelloRequest request,
                         io.grpc.stub.StreamObserver<com.bolingcavalry.grpctutorials.lib.HelloReply> responseObserver) {
        HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName() + ", " + new Date()).build();
        responseObserver.onNext(reply);
        responseObserver.onCompleted();
    }
}
  • There are several points to note in the above GrpcServerService.java:
  1. Use the @ GrpcService annotation and inherit SimpleImplBase, so that sayHello can be exposed as a gRPC service with the help of gRPC server spring boot starter library;
  2. SimpleImplBase is the java code automatically generated according to proto in the previous article, which is in the grpc lib module;
  3. After completing the business logic in the sayHello method, the HelloReply.onNext method is called to fill in the return content.
  4. Call the HelloReply.onCompleted method to indicate that the gRPC service is completed this time;
  • At this point, the gRPC server coding is completed, and we then start the client development;

Call gRPC

  • Create a new module named local client under the parent project grpc tutorials. Its build.gradle content is as follows. Note that you should use the spingboot plug-in and rely on the grpc client spring boot starter Library:
plugins {
    id 'org.springframework.boot'
}

dependencies {
    implementation 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'net.devh:grpc-client-spring-boot-starter'
    implementation project(':grpc-lib')
}
  • Apply the configuration file gRPC tutorials / local client / SRC / main / resources / application.yml. Note that the value of address is the information of gRPC server. Here, local server and local client run on the same computer. Please set it according to your own situation:
server:
  port: 8080
spring:
  application:
    name: local-grpc-client

grpc:
  client:
    # The name of gRPC configuration. GrpcClient annotation will be used
    local-grpc-server:
      # gRPC server address
      address: 'static://127.0.0.1:9898'
      enableKeepAlive: true
      keepAliveWithoutCalls: true
      negotiationType: plaintext

-Next, create the class shown in the following figure in sequence:

  • The first is the interception class LogGrpcInterceptor, which is similar to the interception class on the server side, but the implemented interfaces are different:
package com.bolingcavalry.grpctutorials;

import io.grpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogGrpcInterceptor implements ClientInterceptor {

    private static final Logger log = LoggerFactory.getLogger(LogGrpcInterceptor.class);

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
            CallOptions callOptions, Channel next) {
        log.info(method.getFullMethodName());
        return next.newCall(method, callOptions);
    }
}
  • In order to make the interception class work normally, that is, it is executed when launching gRPC requests, a new configuration class needs to be added:
package com.bolingcavalry.grpctutorials;

import io.grpc.ClientInterceptor;
import net.devh.boot.grpc.client.interceptor.GrpcGlobalClientInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@Order(Ordered.LOWEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
public class GlobalClientInterceptorConfiguration {

    @GrpcGlobalClientInterceptor
    ClientInterceptor logClientInterceptor() {
        return new LogGrpcInterceptor();
    }
}
  • Startup class:
package com.bolingcavalry.grpctutorials;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LocalGrpcClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(LocalGrpcClientApplication.class, args);
    }
}
  • Next is the most important service class GrpcClientService. Several points to note will be mentioned later:
package com.bolingcavalry.grpctutorials;

import com.bolingcavalry.grpctutorials.lib.HelloReply;
import com.bolingcavalry.grpctutorials.lib.HelloRequest;
import com.bolingcavalry.grpctutorials.lib.SimpleGrpc;
import io.grpc.StatusRuntimeException;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;

@Service
public class GrpcClientService {

    @GrpcClient("local-grpc-server")
    private SimpleGrpc.SimpleBlockingStub simpleStub;

    public String sendMessage(final String name) {
        try {
            final HelloReply response = this.simpleStub.sayHello(HelloRequest.newBuilder().setName(name).build());
            return response.getMessage();
        } catch (final StatusRuntimeException e) {
            return "FAILED with " + e.getStatus().getCode().name();
        }
    }
}
  • The above GrpcClientService class has several points to pay attention to:
  1. Register GrpcClientService as a common bean instance of spring with @ Service;
  2. Modify simpleblockingsub with @ GrpcClient, so that gRPC can be called through gRPC client spring boot starter library. The information of the called server comes from the configuration named local gRPC server;
  3. Simpleblockingsub comes from the java code generated according to helloworld.proto above;
  4. The simpleblockingsub.sayhello method will remotely call the gRPC service of the local server application;
  • In order to verify whether the gRPC service call is successful, a new web interface will be added. GrpcClientService.sendMessage will be called inside the interface, so that we can verify whether the gRPC service call is successful through the browser:
package com.bolingcavalry.grpctutorials;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GrpcClientController {

    @Autowired
    private GrpcClientService grpcClientService;

    @RequestMapping("/")
    public String printMessage(@RequestParam(defaultValue = "will") String name) {
        return grpcClientService.sendMessage(name);
    }
}
  • After the coding is completed, start both services to verify whether the gRPC service is normal;

Validate gRPC service

  1. Local server and local client are common springboot applications that can be started in IDEA. Click the red box in the figure below and select Run 'local server application' in the pop-up menu to start local server:
  1. After the local server is started, the console will prompt that gRPC server is started and listening to port 9898, as shown in the following figure:
  1. After local client, enter in the browser http://localhost:8080/?name=Tom , you can see that the content of the response is GrpcServerService.java from the local server:
  1. The key node information from the web side to the gRPC server is shown in the following figure:
  • You can see the interception log of the local server:
  • There are also local client interception logs:
  • So far, the simplest java version of gRPC service has passed the release and call verification, and the task of this article has been completed. In the next article, we will continue to deeply study the relevant technologies of java version of gRPC;

Posted by aff on Mon, 06 Dec 2021 22:47:54 -0800