接下来我们需要把gRPC和Spring boot整合在一起,这里主要记录我们的整合方式。
项目目录结构
项目的目录结构如下:
123456789101112131415161718
foo-svc
├── foo-svc-proto
│ ├── build.gradle
│ └── src
│ └── main
│ └── proto
│ ├── xx1_service.proto
│ └── xx2_service.proto
├── foo-svc-server
│ ├── build.gradle
│ └── src
│ └── main
│ ├── java
│ └── resources
│ └── application.yml
├── build.gradle
├── gradle.properties
└── settings.gradle
一个gRPC服务的项目由两个子项目组成:
proto项目,里面维护gRPC服务的proto文件
server项目,gRPC服务的具体实现
gradle构建脚本
整个gRPC服务项目使用gradle构建,下面介绍父子项目的各个构建脚本的内容。
根项目foo-svc
foo-svc/settings.gradle:
123
include 'foo-svc-proto'
include 'foo-svc-server'
rootProject.name = 'foo-svc'
foo-svc/build.gradle:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
buildscript {
repositories {
mavenCentral()
}
ext {
springBootVersion = '1.5.4.RELEASE'
}
dependencies {
classpath 'com.github.ben-manes:gradle-versions-plugin:0.11.1'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
}
}
apply plugin:'base'
allprojects {
group = 'com.frognew.svc'
version = version
repositories {
maven {
mavenCentral()
}
}
ext {
grpcVersion = '1.4.0'
grpcSpringBootStarterVersion = '1.1.1.RELEASE'
jasyptSpringBootStarterVersion = '1.12'
mybatisSpringBootStarterVersion = '1.3.0'
logbackVersion = '1.2.2'
slf4jVersion='1.7.25'
protocVersion='3.3.0'
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'com.github.ben-manes.versions'
configurations {
all*.exclude group:'com.sun.xml.bind',module:'jaxb-impl'
all*.exclude group:'xml-apis',module:'xml-apis'
all*.exclude group:'stax',module:'stax-api'
all*.exclude group:'org.slf4j',module:'slf4j-log4j12'
all*.exclude group:'commons-logging'
all*.exclude group:'c3p0'
}
sourceSets.main.resources.srcDirs += "src/main/java"
sourceSets.test.resources.srcDirs += "src/test/java"
compileJava {
sourceCompatibility=1.8
targetCompatibility=1.8
options.encoding='UTF-8'
}
compileTestJava {
sourceCompatibility=1.8
targetCompatibility=1.8
options.encoding='UTF-8'
}
tasks.eclipse.dependsOn cleanEclipse
}上面根项目的构建脚本foo-svc/build.gradle中主要定义了项目通用的依赖版本和一些插件信息,并对项目的构建行为做了一些限制。
子项目foo-svc-proto
foo-svc/foo-svc-proto/build.gradle:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
apply plugin: 'com.google.protobuf'
apply plugin: 'maven-publish'
dependencies {
compile "io.grpc:grpc-netty:${grpcVersion}"
compile "io.grpc:grpc-protobuf:${grpcVersion}"
compile "io.grpc:grpc-stub:${grpcVersion}"
}
sourceSets {
main {
java {
srcDir 'build/generated/source/proto/main/java'
srcDir 'build/generated/source/proto/main/grpc'
}
}
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${protocVersion}"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
}
}
generateProtoTasks {
all()*.plugins {
grpc {
option 'enable_deprecated=false'
}
}
}
}
jar {
exclude("*.proto")
}
task sourceJar(type: Jar) {
from sourceSets.main.allJava
}
publishing {
repositories {
maven {
url "http://192.168.1.10:8081/nexus/content/repositories/snapshots/"
}
}
publications {
mavenJava(MavenPublication) {
from components.java
artifact sourceJar {
classifier "sources"
}
}
}
}
tasks.eclipse.dependsOn compileJava
foo-svc/foo-svc-proto/build.gradle中使用com.google.protobuf插件将src/main/proto中的proto文件编译生成gRPC的java代码。
生成的代码位于build/generated/source/proto/main/java和build/generated/source/proto/main/grpc这两个目录中。
同时将这两个目录添加到了sourceSets.main.java中。使用maven-publish插件可以将构建生成的jar包发布到团队的私有maven仓库中,这样gRPC服务的java客户端可以直接使用仓库中的jar。
子项目foo-svc-server
foo-svc/foo-svc-server/build.gradle:
123456789101112131415161718
apply plugin: 'org.springframework.boot'
dependencies {
compile project(':foo-svc-proto')
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-data-redis'
compile "net.devh:grpc-server-spring-boot-starter:$grpcSpringBootStarterVersion"
compile "org.mybatis.spring.boot:mybatis-spring-boot-starter:$mybatisSpringBootStarterVersion"
compile "com.github.ulisesbocchio:jasypt-spring-boot-starter:$jasyptSpringBootStarterVersion"
compile 'com.fasterxml.jackson.core:jackson-databind'
runtime 'mysql:mysql-connector-java'
runtime 'redis.clients:jedis:2.9.0'
runtime 'org.apache.commons:commons-pool2:2.4.2'
testCompile('org.springframework.boot:spring-boot-starter-test')
}
从子项目foo-svc-server的构建脚本可以看出,foo-svc-server就是一个简单的spring-boot项目。
这里使用了yidongnan/grpc-spring-boot-starter这个项目简化了Spring-boot和gRPC整合的代码。
1234567891011
@GrpcService(Xxx1ServiceGrpc.class)
public class Xxx1ServiceService extends Xxx1ServiceImplBase {
@Override
public void sayHello(SayHelloReq request, StreamObserver responseObserver) {
SayHelloResp.Builder respBuilder = SayHelloResp.newBuilder();
......
responseObserver.onNext(respBuilder.build());
responseObserver.onCompleted();
}
服务的客户端
123456789101112131415161718192021222324
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.frognew.svc.foo.proto.Xxx1ServiceGrpc;
import io.grpc.Channel;
import net.devh.springboot.autoconfigure.grpc.client.GrpcClient;
@SpringBootApplication
public class ClientDemoApplication {
@GrpcClient("foo-svc-server")
private Channel xxx1SvcChannel;
@Bean
public Xxx1ServiceGrpc.Xxx1ServiceBlockingStub xxx1ServiceBlockingStub() {
return Xxx1ServiceGrpc.newBlockingStub(xxx1SvcChannel);
}
public static void main(String[] args) {
SpringApplication.run(ApidemoApplication.class, args);
}
}
将上面的Xxx1ServiceBlockingStub注入到业务组件中直接使用即可。
上面@GrpcClient("foo-svc-server")中会读取客户端项目application.yml中的:
1234567
grpc:client:foo-svc-server:host:- 127.0.0.1port:- 9090
获取gRPC服务的地址和端口。我们的服务最终是发布到Kubernetes中,上面的host和port最终设置成Kubernetes中对应Server的名称和端口即可,服务发现机制由Kubernetes提供。
参考