一、快速开始
1、定义一个服务-useinfo.proto
syntax = "proto3";//标识 proto版本 建议使用proto3
package userinfoservice;//proto包名 避免命名冲突,也可以作为引入其他proto文件时使用
option java_package = "com.example.userinfoservice" ;//生成的类将带有此包名,不指定则使用package
option cc_generic_services = true;
option go_package = "./pb";
option java_outer_classname = "UserInfoEntity";//指定生成后的类名,里面会包含req/res,不指定则使用文件名
message GetUserInfoReq{
string id = 1;
}
message GetUserInfoRes{
string id = 1;
string name = 2;
int32 age = 3;
}
service UserInfoService {
rpc getUserInfo(GetUserInfoReq) returns (GetUserInfoRes);
}
2、通过proto文件生成代码
1) Go
- 安装protoc命令
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
$ export PATH="$PATH:$(go env GOPATH)/bin"
- 生成userinfo.pb.go文件和userinfo_grpc.pb.go
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/userinfo.proto
2) Java
-
将你的proto文件放到src/main/proto和src/test/proto目录,并配置生成代码的插件
-
Gradle生成代码插件:
/* * This file was generated by the Gradle 'init' task. * * This generated file contains a sample Java application project to get you started. * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html */ plugins { // Apply the application plugin to add support for building a CLI application in Java. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions id 'com.google.protobuf' version '0.8.17' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' id 'java' } sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { // Use Maven Central for resolving dependencies. mavenCentral() repositories { maven { url 'https://maven.aliyun.com/repository/google/' } maven { url 'https://maven.aliyun.com/repository/jcenter/'} } } def grpcVersion = '1.48.0' // CURRENT_GRPC_VERSION dependencies { // Use JUnit test framework. testImplementation 'junit:junit:4.13.2' // This dependency is used by the application. implementation 'com.google.guava:guava:30.1.1-jre' implementation "io.grpc:grpc-netty:${grpcVersion}" implementation "io.grpc:grpc-protobuf:${grpcVersion}" implementation "io.grpc:grpc-services:${grpcVersion}" implementation "io.grpc:grpc-stub:${grpcVersion}" } application { // Define the main class for the application. mainClass = 'client.MainApplication' } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.2.0" } plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.4.0' } } generateProtoTasks { all()*.plugins { grpc {} } } }
-
Maven生成代码插件:
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.4.1.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
3、对应生成服务端和客户端
(1 )Java 服务端
package com.example.userinfoservice.impl; import com.example.userinfoservice.UserInfoEntity; import com.example.userinfoservice.UserInfoServiceGrpc; import com.example.userinfoservice.entity.UserInfoData; import com.google.common.collect.Maps; import io.grpc.stub.StreamObserver; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; public class UserInfoServiceImpl extends UserInfoServiceGrpc.UserInfoServiceImplBase { private HashMap<String, UserInfoData> userinfoHashMap = Maps.newHashMap(); @Override public void getUserInfo(UserInfoEntity.GetUserInfoReq request, StreamObserver<UserInfoEntity.GetUserInfoRes> responseObserver) { System.out.println("java服务收到请求"); if (StringUtils.isEmpty(request.getId())){ responseObserver.onError(new Exception("id不能为空")); responseObserver.onCompleted(); return; } if (userinfoHashMap.isEmpty()){ initUserInfoHashMap(); } UserInfoData userInfoData = userinfoHashMap.get(request.getId()); if (userInfoData == null){ responseObserver.onError(new Exception("id不能为空")); responseObserver.onCompleted(); return; } responseObserver.onNext(UserInfoEntity.GetUserInfoRes.newBuilder() .setId(userInfoData.getId()) .setName(userInfoData.getName()) .setAge(userInfoData.getAge()) .build()); responseObserver.onCompleted(); } private void initUserInfoHashMap() { userinfoHashMap.put("1",new UserInfoData("1","小美",24)); userinfoHashMap.put("2",new UserInfoData("2","小强",28)); userinfoHashMap.put("3",new UserInfoData("3","小刚",30)); } }
- 实体 UserInfoData
package com.example.userinfoservice.entity; public class UserInfoData{ private String id; private String name; private int age; public UserInfoData() { } public UserInfoData(String id, String name, int age) { this.id = id; this.name = name; this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
- 服务主类 App
/* * This Java source file was generated by the Gradle 'init' task. */ package com.example.userinfoservice; import com.example.userinfoservice.impl.UserInfoServiceImpl; import io.grpc.Server; import io.grpc.ServerBuilder; import java.io.IOException; import java.util.logging.Logger; public class App { public String getGreeting() { return "Hello World!"; } private static final Logger logger = Logger.getLogger(App.class.getName()); private Server server; private void start() throws IOException { int port = 10080; server = ServerBuilder.forPort(port) .addService(new UserInfoServiceImpl()) .build() .start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread(() -> { // Use stderr here since the logger may have been reset by its JVM shutdown hook. logger.info("*** shutting down gRPC server since JVM is shutting down"); App.this.stop(); logger.info("*** server shut down"); })); } private void stop() { if (server != null) { server.shutdown(); } } /** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } /** * Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { final App server = new App(); server.start(); server.blockUntilShutdown(); } }
(2)Java 客户端
package com.example.userinfoservice; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import java.util.logging.Logger; public class MainApplication { private static final Logger logger = Logger.getLogger(MainApplication.class.getName()); public static void main(String[] args) throws InterruptedException { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 10080) .usePlaintext() .build(); UserInfoServiceGrpc.UserInfoServiceBlockingStub stub = UserInfoServiceGrpc.newBlockingStub(channel); Userinfo.GetUserInfoRes res = stub.getUserInfo( Userinfo.GetUserInfoReq.newBuilder() .setId("1") .build()); logger.info("用户id: " + res.getId() + "\t用户姓名:"+ res.getName() +"\t用户年龄:"+ res.getAge()); channel.shutdown(); } }
(3)go 服务端
- 实现用户服务
package serviceimpl import ( "context" "errors" "grpc-in-action/part1/go/server/pb" "log" ) type UserInfo struct { Id string Name string Age int32 } type UserInfoServiceImpl struct { UserInfoData map[string]*UserInfo pb.UnimplementedUserInfoServiceServer } func (server *UserInfoServiceImpl) GetUserInfo(ctx context.Context, in *pb.GetUserInfoReq) (*pb.GetUserInfoRes, error) { log.Printf("go server收到请求") //初始化一个map if server.UserInfoData == nil{ server.initUserInfoData() } data:= server.UserInfoData[in.Id] if data == nil{ return nil,errors.New("该id不存在") } res := &pb.GetUserInfoRes{ Id: data.Id, Name: data.Name, Age: data.Age, } return res,nil } func (server *UserInfoServiceImpl) initUserInfoData (){ server.UserInfoData = make(map[string]*UserInfo) server.UserInfoData["1"] = &UserInfo{ Id: "1", Name: "小美", Age: 18, } server.UserInfoData["2"] = &UserInfo{ Id: "2", Name: "小刚", Age: 28, } server.UserInfoData["3"] = &UserInfo{ Id: "3", Name: "小王", Age: 20, } }
- 服务主类
package main import ( "google.golang.org/grpc" "google.golang.org/grpc/reflection" "grpc-in-action/part1/go/server/pb" "grpc-in-action/part1/go/server/serviceimpl" "log" "net" ) func main() { lis, err := net.Listen("tcp", "localhost:10080") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() ser := &serviceimpl.UserInfoServiceImpl{} pb.RegisterUserInfoServiceServer(s,ser) log.Printf("start") reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
(4)go 客户端
package main import ( "context" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc" "grpc-in-action/part1/go/client/pb" "log" ) func main() { // Set up a connection to the server. conn, err := grpc.Dial("localhost:10080",grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := pb.NewUserInfoServiceClient(conn) req:= &pb.GetUserInfoReq{Id: "1"} res,err :=c.GetUserInfo(context.Background(),req) if err != nil { log.Fatalf("err:%+v",err) }else { log.Printf("res:%+v",res) } }