目标
实践 gRPC 与 springboot 的整合方式,实现 springboot 版本的 gRPC helloworld,通过编写 springboot 测试用例进行测试。
创建项目
项目文件夹 grpc-spring-boot-helloworld,pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codenotfound</groupId>
<artifactId>grpc-spring-boot-helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>grpc-spring-boot-helloworld</name>
<description>gRPC - Spring Boot Hello World Example</description>
<url>https://www.codenotfound.com/grpc-spring-boot-example.html</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<grpc-spring-boot-starter.version>2.3.2</grpc-spring-boot-starter.version>
<os-maven-plugin.version>1.6.0</os-maven-plugin.version>
<protobuf-maven-plugin.version>0.5.1</protobuf-maven-plugin.version>
</properties>
<repositories>
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
</repositories>
<dependencies>
<!-- spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>${grpc-spring-boot-starter.version}</version>
</dependency>
</dependencies>
<build>
<extensions>
<!-- os-maven-plugin -->
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os-maven-plugin.version}</version>
</extension>
</extensions>
<plugins>
<!-- spring-boot-maven-plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- protobuf-maven-plugin -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf-maven-plugin.version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact>
<outputDirectory>${project.build.sourceDirectory}</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
springboot 主文件 src/main/java/com/codenotfound/grpc/DemoApplication.java
package com.codenotfound.grpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
创建 proto 文件
src/main/proto/HelloWorld.proto
syntax = "proto3";
option java_multiple_files = true;
package com.codenotfound.grpc.helloworld;
message Person {
string first_name = 1;
string last_name = 2;
}
message Greeting {
string message = 1;
}
service HelloWorldService {
rpc sayHello (Person) returns (Greeting);
}
编译
mvn compile
编译后自动生成 proto 描述的相关代码。
实现 service
src/main/java/com/codenotfound/grpc/HelloWorldServiceImpl.java
package com.codenotfound.grpc;
import org.lognet.springboot.grpc.GRpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.codenotfound.grpc.helloworld.Greeting;
import com.codenotfound.grpc.helloworld.HelloWorldServiceGrpc;
import com.codenotfound.grpc.helloworld.Person;
import io.grpc.stub.StreamObserver;
@GRpcService
public class HelloWorldServiceImpl
extends HelloWorldServiceGrpc.HelloWorldServiceImplBase {
private static final Logger LOGGER =
LoggerFactory.getLogger(HelloWorldServiceImpl.class);
@Override
public void sayHello(Person request,
StreamObserver<Greeting> responseObserver) {
LOGGER.info("server received {}", request);
String message = "Hello " + request.getFirstName() + " "
+ request.getLastName() + "!";
Greeting greeting =
Greeting.newBuilder().setMessage(message).build();
LOGGER.info("server responded {}", greeting);
responseObserver.onNext(greeting);
responseObserver.onCompleted();
}
}
创建 client
src/main/java/com/codenotfound/grpc/HelloWorldClient.java
package com.codenotfound.grpc;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.codenotfound.grpc.helloworld.Greeting;
import com.codenotfound.grpc.helloworld.HelloWorldServiceGrpc;
import com.codenotfound.grpc.helloworld.Person;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
@Component
public class HelloWorldClient {
private static final Logger LOGGER =
LoggerFactory.getLogger(HelloWorldClient.class);
private HelloWorldServiceGrpc.HelloWorldServiceBlockingStub helloWorldServiceBlockingStub;
@PostConstruct
private void init() {
ManagedChannel managedChannel = ManagedChannelBuilder
.forAddress("localhost", 6565).usePlaintext().build();
helloWorldServiceBlockingStub =
HelloWorldServiceGrpc.newBlockingStub(managedChannel);
}
public String sayHello(String firstName, String lastName) {
Person person = Person.newBuilder().setFirstName(firstName)
.setLastName(lastName).build();
LOGGER.info("client sending {}", person);
Greeting greeting =
helloWorldServiceBlockingStub.sayHello(person);
LOGGER.info("client received {}", greeting);
return greeting.getMessage();
}
}
测试代码
src/test/java/com/codenotfound/grpc/GRPCApplicationTests.java
package com.codenotfound.grpc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.codenotfound.grpc.HelloWorldClient;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest
public class GRPCApplicationTests {
@Autowired
private HelloWorldClient helloWorldClient;
@Test
public void testSayHello() {
assertThat(helloWorldClient.sayHello("John", "Doe")).isEqualTo("Hello John Doe!");
}
}
运行测试
mvn test
运行效果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
......
2018-09-25 10:55:52.491 INFO 55173 --- [ main] o.l.springboot.grpc.GRpcServerRunner : Starting gRPC Server ...
2018-09-25 10:55:52.504 INFO 55173 --- [ main] o.l.springboot.grpc.GRpcServerRunner : 'com.example.grpc.demo.HelloWorldServiceImpl' service has been registered.
2018-09-25 10:55:52.602 INFO 55173 --- [ main] o.l.springboot.grpc.GRpcServerRunner : gRPC Server started, listening on port 6565.
2018-09-25 10:55:52.679 INFO 55173 --- [ main] com.example.grpc.demo.HelloWorldClient : client sending first_name: "John"
last_name: "Doe"
2018-09-25 10:55:52.951 INFO 55173 --- [ault-executor-0] c.e.grpc.demo.HelloWorldServiceImpl : server received first_name: "John"
last_name: "Doe"
2018-09-25 10:55:52.953 INFO 55173 --- [ault-executor-0] c.e.grpc.demo.HelloWorldServiceImpl : server responded message: "Hello John Doe!"
2018-09-25 10:55:52.962 INFO 55173 --- [ main] com.example.grpc.demo.HelloWorldClient : client received message: "Hello John Doe!"
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.05 s - in com.example.grpc.demo.GRPCApplicationTests
2018-09-25 10:55:53.032 INFO 55173 --- [ Thread-2] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@2e385cce: startup date [Tue Sep 25 10:55:50 CST 2018]; root of context hierarchy
2018-09-25 10:55:53.034 INFO 55173 --- [ Thread-2] o.l.springboot.grpc.GRpcServerRunner : Shutting down gRPC server ...
2018-09-25 10:55:53.036 INFO 55173 --- [ Thread-2] o.l.springboot.grpc.GRpcServerRunner : gRPC server stopped.
参考文章: