Dubbo的簡單使用以及Triple協議的Streaming通訊的實現

WasteCode發表於2022-11-24
商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.
協議(License):署名-非商業性使用-相同方式共享 4.0 國際 (CC BY-NC-SA 4.0)
作者(Author):Waste Code
連結(URL):https://waste-code.tech/archi...
來源(Source):Waste Code

文章概覽

Dubbo的簡單使用

  1. 在common模組中定義實體類User
  2. 在common模組中宣告暴露出的介面,實現介面UserService

    public interface UserService {
    
        /**
        * 獲取使用者資訊
        * @param name
        * @return
        */
        User getUserInfo(String name);
    }
  3. 在provider和consumer模組中引入相關依賴

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.7</version>
    </dependency>
    
    <!--   下面這個包必須引用,服務註冊到zookeeper中使用,之前沒有引用這個包,結果應用起不來         -->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-zookeeper</artifactId>
        <version>3.0.7</version>
    </dependency>
    
    <dependency>
        <groupId>com.sample</groupId>
        <artifactId>common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
  4. 在provider和consumer模組中建立application.yml檔案並編寫相關配置

    server:
        port: 8082 # 這裡填寫埠號,provider和consumer不同,
    spring:
        application:
            name: consumer
    
    dubbo:
        protocol:
            name: dubbo # 選擇通訊協議
            port: -1
        registry:
            id: zk-zookeeper
            address: zookeeper://127.0.0.1:2181
  5. 在provider和consumer中編寫啟動類,這裡以consumer模組為例,這裡要加上EnableDubbo註解

    @SpringBootApplication
    @EnableDubbo
    public class ConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
  6. 在provider中對UserService進行實現

    // 這裡注意使用註解@DubboService,時dubbo中的Service註解,主要在對外提供服務的實現類上
    @DubboService
    public class UserServiceImpl implements UserService {
        @Override
        public User getUserInfo(String name) {
            User user = new User();
            user.setName("dubbo");
            user.setAge(12);
            return user;
        }
    
    }
    
  7. 在consumer中實現請求介面, 引用provider模組暴露出的介面要使用DubboReference註解

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @DubboReference
        private UserService userService;
    
        @GetMapping("/info")
        public User getUserInfo() {
            return userService.getUserInfo("xxx");
        }
    
    
    }

編寫完成程式碼後,啟動provider和consumer模組,然後透過Postman工具呼叫介面,發現可以正常使用就完成了

Triple協議的Streaming通訊實現

Triple協議的Stream通訊主要分為三種:服務端流、客戶端流、雙向流

應用場景

  • 介面需要傳送大量資料,無法被放到一次請求中,需要分批次傳送
  • 流式場景,資料需要按照傳送順序處理, 資料本身是沒有確定邊界的
  • 推送類場景,多個訊息在同一個呼叫的上下文中被髮送和處理

    流的語義保證(優點)

  • 提供訊息邊界,可以方便的對訊息進行單獨處理
  • 嚴格有序,傳送端的順序和接收端的順序是一致的
  • 全雙工,傳送不需要等待
  • 支援取消和超時

Streaming流通訊實現

服務端流(SERVER_STREAM)請求流程

image.png

服務端流(SERVER_STREAM)的Java實現

  1. 在provider和consumer模組中新增相關依賴

    <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
    </dependency>
  2. 修改provider和consumer模組中的相關配置

    dubbo: #此處僅擷取需要變更的配置,其他配置預設為有原有的就行
        protocol:
            name: tri # 修改dubbo的通訊協議,當然triple協議同樣支援之前的dubbo的簡單使用
  3. 在common模組的UserService中宣告相關api介面

    /**
     * 服務端流
     * @param name
     * @param response
     */
    void sayHelloServerStream(String name, StreamObserver<String> response)
        throws InterruptedException;
  4. 在provider模組中實現相關功能

    //StreamObserver是接收訊息的觀察者,
    //在onNext方法呼叫後,consumer模組中的消費者會獲取相關的資料,
    //當onCompleted方法呼叫後,consumer模組進行最後的處理後,整個服務端流才會結束
    @Override
    public void sayHelloServerStream(String name, StreamObserver<String> response)
        throws InterruptedException {
    
        response.onNext("Hallo, " + name);
        
        // 這裡延遲10s,主要測試,provider模組接收資料會不會有10s的延時
        Thread.sleep(10 * 1000);
    
        response.onNext("Hallo, " + name + ", 第二次");
    
        response.onCompleted();
    }
  5. 在consumer模組編寫請求方法

    
    /**
     * 測試服務端流
     * @param name
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/sayHallo/{name}")
    public List<String> sayHallo(@PathVariable("name") String name) throws InterruptedException {
    
        List<String> list = new ArrayList<>();
        userService.sayHelloServerStream(name, new StreamObserver<String>() {
            
            // 每次provider模組呼叫一次onNext時,該方法會執行一次
            @Override
            public void onNext(String data) {
                System.out.println("onNext:" + data);
                list.add(data);
            }
    
            @Override
            public void onError(Throwable throwable) {
                System.out.println("報錯了");
            }
            // 當provider模組的onCompleted方法呼叫後,執行該方法
            @Override
            public void onCompleted() {
                System.out.println("結束");
            }
        });
        return list;
    }

    客戶端(CLIENT_STREAM)流請求流程

    image.png

雙向流(BIDIRECTIONAL_STREAM)請求流程

image.png

客戶端流(CLIENT_STREAM)/雙向流(BIDIRECTIONAL_STREAM)的Java實現

  1. 客戶端流和雙向流在Java中的實現方式是同一種
  2. 引用pom和修改配置與服務端流相同
  3. 在common模組中宣告相關介面

    /**
     * 客戶端流/雙向流, 這裡返回的StreamObserver類裡的處理實在provider模組中實現,
     * 而引數StreamObserver則是在consumer模組中實現,雖然是consumer呼叫該方法
     * @param response
     * @return
     */
    StreamObserver<String> sayHelloStream(StreamObserver<String> response);
  4. 在provider模組中實現相關方法

    @Override
    public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
        return new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println("服務端請求引數:" + data);
                response.onNext("Hello, " + data);
            }
    
            @Override
            public void onError(Throwable throwable) {
    
            }
    
            @Override
            public void onCompleted() {
                System.out.println("provider關閉");
                response.onCompleted();
            }
        };
    }
  5. 在consumer模組中實現方法的呼叫

    
    @PostMapping("/sayHallo")
    public List<String> sayHallo(@RequestBody List<String> names) {
        List<String> list = new ArrayList<>();
        StreamObserver<String> request = userService.sayHelloStream(new StreamObserver<String>() {
            @Override
            public void onNext(String data) {
                System.out.println("說了啥?" + data);
                list.add(data);
            }
    
            @Override
            public void onError(Throwable throwable) {
    
            }
    
            @Override
            public void onCompleted() {
                System.out.println("結束了");
            }
        });
    
        // 上面定義了StreamObserver並呼叫了方法後,在下邊透過onNext方法呼叫傳送請求
        names.forEach(item -> {
            request.onNext(item);
            try {
                Thread.sleep(10 * 1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        request.onCompleted();
    
        return list;
    }

相關文章