1. Grpc介绍
在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。
1.1 传统rpc对比Grpc
- 传统RPC框架:使用各种协议和编码方式进行通信,可能导致跨语言通信困难、性能不佳等问题;
- GRPC框架:使用Google开发的ProtoBuf进行序列化、并通过http/2(多路复用)进行通信,通信效率更加高效;
1.2 GRPC的优势
- 高性能:使用二进制的ProtoBuf编码和http/2多路复用机制等技术,实现低延迟和高吞吐的通信;
- 支持多语言:C++、Java、Python、Go等等;
- 强类型:使用ProtoBuf定义消息和接口,消除了手动解析数据的麻烦;
- 双向流式通信:GRPC支持双向流式传输,适用于实时性要求高的场景;
- 自动代码生成:根据定义好的服务接口和消息,GRPC自动生成客户端和服务端的代码,简化开发流程;
1.3 GRPC在分布式系统中的应用场景
- 微服务通信;
- 跨数据中心通信;
- 实时通信;
java实现Grpc调用
1. Java项目简介
2. study_GRPC父项目
<?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>
<!-- 第一步:引入核心依赖,父项目 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
</parent>
<groupId>org.example</groupId>
<artifactId>study_GRPC</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!-- 三个子模块 -->
<modules>
<module>GRPC_service</module>
<module>GRPC_client</module>
<module>springboot-grpc-lib</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 第二步:引入web项目依赖,会导入tomcat等依赖启动Springboot
该依赖会引入 @Service @Component @RestController tomcat等等
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
3. springboot-grpc-lib子模块
3.1 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">
<parent>
<artifactId>study_GRPC</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springboot-grpc-lib</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>8</java.version>
<protobuf.version>3.23.4</protobuf.version>
<grpc.version>1.26.0</grpc.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<!-- grpc server和spring-boot集成框架 -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>
<!-- grpc client和spring-boot集成框架 -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<!-- os系统信息插件, protobuf-maven-plugin需要获取系统信息下载相应的protobuf程序 -->
<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>
<!--os.detected.classifier属性是通过如上os-maven-plugin插件获取的-->
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
</pluginArtifact>
<!-- proto文件目录 -->
<protoSourceRoot>${project.basedir}/src/main/java/com/cxp/generateProto</protoSourceRoot>
<!-- 生成的Java文件目录,这里指定到这一级就可以咯,proto文件有基于package指定 -->
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.2 项目目录
3.3 hello.proto
// 说明使用的是:proto3语法
syntax = "proto3";
// java_package表示生成java代码的包名
option java_package = "com.cxp.generateProto.protogen";
// java_multiple_files = true 表示生成多个java文件,若不设置该属性,则只会生成一个java文件
option java_multiple_files = true;
// java_outer_classname表示包含message描述的java文件的类名
option java_outer_classname = "HelloWorldProto";
// 定义一个服务,服务中可以编写多个方法。方法可以接受客户端的参数,再返回服务端的响应。
service HelloWorld {
// 方法:接受 HelloRequest,返回 HelloResp
rpc sayHello(HelloRequest) returns (HelloResp) {}
}
// message关键字表示结构体
message HelloRequest {
// 赋值是为了定义这个变量在message中的位置
string name = 1;
int32 id = 2;
}
message HelloResp {
string school = 1;
string address = 2;
int32 age = 3;
}
3.4 生成protobuf文件
4. GRPC_service子模块
4.1 pom.xml文件
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot-grpc-lib</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
4.2 application.yml文件
server:
port: 8080
grpc:
server:
# 指定Grpc暴露的端口,后续客户端通过这个端口访问
port: 9090
4.3 Grpc接口实现类
一定记得加
@GrpcService
注解,表明这个是Grpc服务接口的实现类!!!
import com.cxp.generateProto.protogen.HelloRequest;
import com.cxp.generateProto.protogen.HelloResp;
import com.cxp.generateProto.protogen.HelloWorldGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
/**
* @Author: Thomas
* @Date: 2023-10-05 21:56:45
* @Description:
*/
@GrpcService
public class HelloWorldProtoImpl extends HelloWorldGrpc.HelloWorldImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloResp> responseObserver) {
String name = request.getName();
int id = request.getId();
System.out.println(name + " ---------------------- " + id);
/**
* 这里可以写具体的业务逻辑进行实现!!!!
*/
HelloResp helloResp = HelloResp.newBuilder()
.setSchool("DMU")
.setAddress("贵州遵义")
.setAge(123)
.build();
responseObserver.onNext(helloResp);
responseObserver.onCompleted();
}
}
4.4 项目目录
5. GRPC_client子模块
5.1 pom.xml文件
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>springboot-grpc-lib</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<!-- 排除GRPC的服务器依赖,避免客户端也需要暴露Grpc服务端口 -->
<exclusion>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
5.2 基于GRPC server的URL直接调用【非Springboot调用】
public class FramelessGrpcClient {
public static void main(String[] args) {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9090).usePlaintext().build();
HelloWorldGrpc.HelloWorldBlockingStub heelloWorldService = HelloWorldGrpc.newBlockingStub(managedChannel);
HelloRequest helloRequest = HelloRequest.newBuilder()
.setName("cxplovezm")
.setId(10000)
.build();
System.out.println("get response-------->");
HelloResp helloResp = heelloWorldService.sayHello(helloRequest);
System.out.println(helloResp);
System.out.println(helloResp.getSchool() + " " + helloResp.getAddress() + " " + helloResp.getAge());
}
}
- 测试
- 启动服务端
- 运行
FramelessGrpcClient
代码
5.3 基于Springboot的IOC注入调用
5.3.1 application.yml文件
server:
port: 8081
grpc:
client:
# 可以申明多个Grpc服务的ip和端口,后续注入通过 userClient 注入
userClient:
negotiationType: PLAINTEXT
address: localhost:9090
5.3.2 controller控制器
@RestController
@RequestMapping("/hello")
public class HelloController {
@Resource
private HelloWorld helloWorld;
@GetMapping("/world")
public String getWorld() {
System.out.println(" ---------- 进入Springboot的Grpc的client -----------");
return helloWorld.getHelloWorld();
}
}
5.3.3 服务接口
- 服务
public interface HelloWorld {
String getHelloWorld();
}
- 实现类
@Service
public class HelloworldImpl implements HelloWorld {
// 注意:这里的userClient需要和applicaiotn.yml中的userClient一致,当调用多个grpc服务时候,可以用于区分!!!
@GrpcClient("userClient")
private HelloWorldGrpc.HelloWorldBlockingStub helloWorldClient;
@Override
public String getHelloWorld() {
HelloRequest helloRequest = HelloRequest.newBuilder()
.setName("cxplovezm")
.setId(10000)
.build();
HelloResp helloResp = helloWorldClient.sayHello(helloRequest);
return helloResp.getSchool() + " " + helloResp.getAddress() + " " + helloResp.getAge();
}
}
5.3.4 测试
- 客户端启动类
@SpringBootApplication
public class GRPCClientApplication {
public static void main(String[] args) {
SpringApplication.run(GRPCClientApplication.class, args);
}
}
- 启动服务器;
- 启动客户端;
- 浏览器输入:
http://localhost:8081/hello/world
成功!!!!