前言
前段时间团队开始采用了grpc作为内部服务通讯技术,部份服务已按照grpc实现也陆续上线了,在实际使用过程中,发现grpc在java应用方面,很多地方还是可以优化的,比如:
- grpc 接口出入参实体与java pojo的数据转化和共用性方面
- grpc 基于spring boot 的集成方案启动框架,目前还没有官方版本,项目使用第三方net.devh下的grpc-server-spring-boot-starter框架(后续,也准备打造自己springboot-starter)
对比之下,dubbo体系,这一块做得比较完善,所以自己抽空研究了下dubbo,发现dubbo也是可以支持grpc协议,所以捣鼓了下Grpc+Dubbo+Spring Boot的整合
阅读本文建议先了解dubbo框架
http://dubbo.apache.org/zh/docs/v2.7/user/preface/architecture/参考文章: Dubbo在跨语言和协议穿透性方向的探索:支持 HTTP/2 gRPC
https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247488245&idx=2&sn=b59960420b4e7ae65bb813d4215601a2&chksm=fdeb2095ca9ca983a8da5379b29191c7cba256aaf287966d419d25a9606187805249c8988d63&scene=27#wechat_redirect
项目结构说明
├── dubbo-grpc-api(接口工程,供消费端和服务端引用)
│ ├── build(编译后grpc的接口文件)
│ ├── pom.xml(利用Protobuf Compiler工具,生成代码)
│ └── src
│ └── main
│ ├── java
│ ├── proto
│ │ └── helloworld.proto(IDL描述文件)
├── dubbo-grpc-consumer(消费端)
│ ├── pom.xml
│ └── src
├── dubbo-grpc-provider(服务端)
│ ├── pom.xml
│ └── src
└── pom.xml
项目代码
https://gitee.com/hushow/learning-demo/tree/master/grpc-dubbo-example/spring-cloud-dubbo-grpc-demo
1. 依赖版本
- spring-boot 2.2.6.RELEASE
- dubbo.version 2.7.7
- dubbo-compiler 0.0.1
- dubbo-spring-boot-starter 2.7.7
- grpc 1.30.0
- protobuf-java-util 3.12.0
- protoc 3.12.0
2. 准备zookeeper实例
服务提供端和和消费端都要依赖注册中心,本例使用zookeeper做为服务注册中心
docker方式启动zookeeper
docker run --publish 2181:2181 --name zoo zookeeper:latest
3. dubbo-grpc-api
将IDL文件独立出来,做成共享api工程,既单一原则又避免了每个工程都依赖IDL编译细节
3.1 定义IDL
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.hushow.demo.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;
}
3.2 使用dubbo定制的Maven Protobuf Compiler 插件
与grpc原生配置不同之处为Dubbo团队扩展了 Protobuf 的 Compiler 工具,以用来生成 Dubbo 特有的 RPC stub
grpc原生Protobuf Compiler配置参考文章
http://www.hushowly.com/articles/1565
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<outputDirectory>build/generated/source/proto/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
<protocPlugins>
<protocPlugin>
<id>dubbo-grpc</id>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-compiler</artifactId>
<version>${dubbo.compiler.version}</version>
<mainClass>org.apache.dubbo.gen.grpc.DubboGrpcGenerator</mainClass>
</protocPlugin>
</protocPlugins>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
<goal>test-compile</goal>
<goal>test-compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
3.3 编译打包
dubbo-grpc-api$ mvn clean install
4. dubbo-grpc-provider
4.1 引用以上api接口
<dependency>
<groupId>com.hushow.demo</groupId>
<artifactId>dubbo-grpc-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
4.2 实现业务逻辑
此处使用注解暴露的服务,dubbo也支持xml配置暴露方式
@DubboService
public class GrpcGreeterImpl extends DubboGreeterGrpc.GreeterImplBase implements DubboGreeterGrpc.IGreeter{
public GrpcGreeterImpl() {
System.out.println("GrpcGreeterImpl.GrpcGreeterImpl");
}
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
System.out.println("Executing thread is " + Thread.currentThread().getName());
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
注细节:
1.必须继承DubboGreeterGrpc.GreeterImplBase
2.声明DubboService注解,对外暴露Dubbo服务
3.如果使用注解暴露服务,还需要实现DubboGreeterGrpc.IGreeter接口,否则会报ClassNotFoundMethods异常,本人已踩坑过程
4.3 dubbo配置信息
dubbo:
#指定grpc协议
protocol:
id: grpc
name: grpc
#指定注册中心
registry:
address: zookeeper://127.0.0.1:2181
#address: nacos://127.0.0.1:8848
#服务名称
application:
id: dubbo-grpc-provider-web
name: dubbo-grpc-provider-web
4.4 spring boot 启动
@EnableAutoConfiguration
@EnableDubbo(scanBasePackages="com.hushow.demo.helloworld.service.impl")
public class ProviderApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ProviderApplication.class).run(args);
}
}
注细节:
使用EnableDubbo启用dubbo,并指定暴露服务包范围
5. dubbo-grpc-consumer
5.1 引用以上api接口
<dependency>
<groupId>com.hushow.demo</groupId>
<artifactId>dubbo-grpc-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
5.2 编写消费测试Controller
@RestController
@Slf4j
@RequestMapping("grpc")
public class RpcProxyController {
@DubboReference
private DubboGreeterGrpc.IGreeter greeter;
@RequestMapping("/hello")
public String hello(@RequestParam("name") String name){
log.info("yyyyy hRpcProxyController.hello:{}", name);
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response = greeter.sayHello(request);
return response.getMessage();
}
}
注意细节
通过DubboReference注解声明为服务的订阅者,且要注入的是DubboGreeterGrpc.IGreeter接口
5.3 dubbo配置信息
spring:
application:
name: dubbo-grpc-consumer-web
#bean可覆盖模式,否则启动会报错
main:
allow-bean-definition-overriding: true
server:
port: 8085
dubbo:
#注册中心
registry:
address: zookeeper://127.0.0.1:2181
#address: nacos://127.0.0.1:8848
#指定dubbo协议
protocol:
id: grpc
name: grpc
#服务名
application:
id: dubbo-grpc-consumer-web
name: dubbo-grpc-consumer-web
5.4 消费端启动
@EnableAutoConfiguration
@ComponentScan("com.hushow.demo")
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ConsumerApplication.class).run(args);
}