在Spring boot 2 微服務中使用 GRPC

在Spring boot 2 微服務中使用 GRPC

關於RPC

RPC(Remote Procedure Call)—遠程過程調用,它是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。java

gRPC

gRPC是Google開源的通用高性能RPC框架,它支持的是使用Protocol Buffers來編寫Service定義,支持較多語言擴平臺而且擁有強大的二進制序列化工具集。與文章《RPC框架實踐之:Apache Thrift》一文中實踐的另外一種通用RPC框架Thrift能經過Generator自動生成對應語言的Service接口相似,gRPC也能自動地生成Server和Client的Service存根(Stub),咱們只須要一個命令就能快速搭建起RPC運行環境。git

微服務和 RPC

微服務大行其道的今天,服務間通信實際上是個比較大的問題,REST調用及測試都很方便,RPC就顯得有點繁瑣,可是RPC的效率是毋庸置疑的,因此建議在多系統之間的內部調用採用RPC。對外提供的服務,Rest更加合適。github

若是何用

  • 在一個 .proto 文件內定義服務。
  • 用 protocol buffer 編譯器生成服務器和客戶端代碼。
  • 使用 gRPC 的 Java API 爲你的服務實現一個簡單的客戶端和服務器。

Demo

建立一個Spring boot 2項目,選擇Web StarterLombok就能夠了。而後加入對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...

資源

相關文章
相關標籤/搜索