RPC(Remote Procedure Call)—遠程過程調用,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。java
gRPC是Google開源的通用高性能RPC框架,它支持的是使用Protocol Buffers來編寫Service定義,支持較多語言擴平臺而且擁有強大的二進制序列化工具集。與文章《RPC框架實踐之:Apache Thrift》一文中實踐的另外一種通用RPC框架Thrift能經過Generator自動生成對應語言的Service接口相似,gRPC也能自動地生成Server和Client的Service存根(Stub),咱們只須要一個命令就能快速搭建起RPC運行環境。git
在微服務
大行其道的今天,服務間通信實際上是個比較大的問題,REST
調用及測試都很方便,RPC就顯得有點繁瑣,可是RPC的效率是毋庸置疑的,因此建議在多系統之間的內部調用採用RPC。對外提供的服務,Rest更加合適。github
建立一個Spring boot 2項目,選擇Web Starter
和Lombok
就能夠了。而後加入對grpc-spring-boot-starter
的依賴。spring
<dependency> <groupId>io.github.lognet</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>3.4.1</version> </dependency>
編譯須要修改,由於編譯時須要先.proto
文件進行代碼生成,生成咱們想要的java代碼文件。生成的文件會在target下的generated-source下的protobuf文件夾下。編譯配置以下:json
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>${os-maven-plugin.version}</version> </extension> </extensions> <plugins> <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.9.1:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact> io.grpc:protoc-gen-grpc-java:1.23.0:exe:${os.detected.classifier} </pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
添加三個.proto
文件,第一個是Member.proto
文件,做爲一個複合對象,做爲參數使用。瀏覽器
syntax = "proto3"; option java_multiple_files = true; package com.example.grpcdemo.grpc; message Member { string username = 1; string password = 2; string info = 3; }
而後就是Service文件,MemberListSerbice.proto
文件中定義了,request和respone的內容,還有服務輸入輸出的message。這裏須要引入以前定義的Member.proto
服務器
syntax = "proto3"; option java_multiple_files = true; package com.example.grpcdemo.grpc; import "Member.proto"; message MemberListRequest { int32 page = 1; int32 per_page = 2; } message MemberListResponse { repeated Member member = 1; } service MemberListService { rpc member_list(MemberListRequest) returns (MemberListResponse); }
這裏另外一個Service詳見源代碼。下面添加一些本項目所需的RPC服務處理代碼,先編譯項目,省城所需java文件,而後就能夠開始寫RPC服務處理代碼,須要從生成的抽象類繼承。網絡
@GRpcService public class MemberLoginServiceImpl extends MemberLoginServiceGrpc.MemberLoginServiceImplBase { @Override public void memberLogin(MemberLoginRequest request, StreamObserver<MemberLoginResponse> responseObserver) { String token = ""; if(request.getMember().getPassword().equals("123456")){ token = "success"; } MemberLoginResponse response = MemberLoginResponse .newBuilder() .setToken(token) .build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }
還須要一個Java類來定義客戶端鏈接RPC所需的Beanapp
@Configuration public class GrpcConfig { @Bean ManagedChannel channel(@Value("${app-config.grpc-server-name}") String name, @Value("${app-config.grpc-server-port}") Integer port){ return ManagedChannelBuilder.forAddress(name, port) .usePlaintext() .build(); } @Bean MemberListServiceGrpc.MemberListServiceBlockingStub memberListServiceBlockingStub(ManagedChannel channel){ return MemberListServiceGrpc.newBlockingStub(channel); } @Bean MemberLoginServiceGrpc.MemberLoginServiceBlockingStub memberLoginServiceStub(ManagedChannel channel){ return MemberLoginServiceGrpc.newBlockingStub(channel); } }
最後還有一個測試用的Controller,瀏覽器訪問controller中的rest服務,rest服務鏈接rpc去訪問真實服務,這裏服務端和客戶端並無分開,實際controller應該在真正的客戶端項目中。這裏只是一個demo框架
@RestController public class MemberController{ private MemberListServiceGrpc.MemberListServiceBlockingStub memberListServiceBlockingStub; private MemberLoginServiceGrpc.MemberLoginServiceBlockingStub memberLoginServiceBlockingStub; public MemberController(MemberListServiceGrpc.MemberListServiceBlockingStub memberListServiceBlockingStub, MemberLoginServiceGrpc.MemberLoginServiceBlockingStub memberLoginServiceBlockingStub) { this.memberListServiceBlockingStub = memberListServiceBlockingStub; this.memberLoginServiceBlockingStub = memberLoginServiceBlockingStub; } /** * curl -X POST -H "Content-type: application/json" -d "{\"username\":\"freewolf\", \"password\":\"123456\"}" http://localhost:8080/login * @param memberVO * @return */ @PostMapping("/login") public String login(@RequestBody MemberVO memberVO){ MemberLoginResponse response = this.memberLoginServiceBlockingStub.memberLogin(MemberLoginRequest.newBuilder() .setMember(Member.newBuilder() .setPassword(memberVO.getPassword()) .setUsername(memberVO.getUsername()) .build()) .build()); return response.getToken(); } @GetMapping("/list") public List<MemberVO> list(){ MemberListResponse response = this.memberListServiceBlockingStub.memberList(MemberListRequest.newBuilder() .setPage(1) .setPerPage(2) .build()); List<MemberVO> list = MemberVO.getList(response.getMemberList()); return list; } }
本文代碼地址: https://github.com/freew01f/g...