Springboot2.2中的RSocket體驗

Springboot2.2中的RSocket體驗

什麼是RSocket?

RSocket是一種二進制協議,用於TCP、websocket和Aeron等字節流傳輸。它通過異步消息在單個連接上傳遞,支持以下對稱交互模型:

  1. request/response (stream of 1)
  2. request/stream (finite stream of many)
  3. fire-and-forget (no response)
  4. channel (bi-directional streams)

一個發展過程

下面是一個簡單的demo,包括兩個模塊producer和consumer供大家學習.

producer

核心pom.xml

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-rsocket</artifactId>
        </dependency>

Repository

@Slf4j
@Component
public class MarketDataRepository {

    private static final int BOUND = 100;

    private Random random = new Random();

    public Flux<MarketData> getAll(String stock) {
        return Flux.fromStream(Stream.generate(() -> getMarketDataResponse(stock)))
                .log()
                .delayElements(Duration.ofSeconds(1));
    }

    public Mono<MarketData> getOne(String stock) {
        return Mono.just(getMarketDataResponse(stock));
    }

    public void add(MarketData marketData) {
        log.info("New market data: {}", marketData);
    }

    private MarketData getMarketDataResponse(String stock) {
        return new MarketData(stock, random.nextInt(BOUND));
    }
}

這個MarketDataRepository是一個簡易模擬,當然你也可以使用R2DBC猛戳

controller

@Controller
public class MarketDataRSocketController {
    private final MarketDataRepository marketDataRepository;

    public MarketDataRSocketController(MarketDataRepository marketDataRepository) {
        this.marketDataRepository = marketDataRepository;
    }

    @MessageMapping("currentMarketData")
    public Mono<MarketData> currentMarketData(MarketDataRequest marketDataRequest) {
        return marketDataRepository.getOne(marketDataRequest.getStock());
    }

    @MessageMapping("feedMarketData")
    public Flux<MarketData> feedMarketData(MarketDataRequest marketDataRequest) {
        return marketDataRepository.getAll(marketDataRequest.getStock());
    }

    @MessageMapping("collectMarketData")
    public Mono<Void> collectMarketData(MarketData marketData) {
        marketDataRepository.add(marketData);
        return Mono.empty();
    }

    @MessageExceptionHandler
    public Mono<MarketData> handleException(Exception e) {
        return Mono.just(MarketData.fromException(e));
    }
}

這個Controller用來處理消費者的RSocket請求,
注意這裏的@MessageMapping其實可以理解爲就是@RequestMapping,其實就是提供路由.

application.properties

spring.rsocket.server.port=7000

配置,目前只有四個,可以參考這裏

異常處理

@MessageExceptionHandler
public Mono<MarketData> handleException(Exception e) {
    return Mono.just(MarketData.fromException(e));
}

注意:不同的模式需要不同的異常處理,這裏是針對請求/響應的異常處理,啦啦啦.

consumer

核心pom.xml

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-rsocket</artifactId>
        </dependency>

配置Configuration

@Lazy
@Configuration
public class ConsumerConfiguration {

    @Bean
    RSocket rSocket() {
        return RSocketFactory
                .connect()
                .dataMimeType(MimeTypeUtils.APPLICATION_JSON_VALUE)
                .frameDecoder(PayloadDecoder.ZERO_COPY)
                //.transport(TcpClientTransport.create("47.96.70.206",7000)) 個人服務器已關閉
                .transport(TcpClientTransport.create("127.0.0.1",7000))
                .start()
                .block();
    }

    @Bean
    RSocketRequester requester(RSocketStrategies rSocketStrategies) {

        //廢棄版
        //RSocketRequester.create(this.rSocket(),MimeTypeUtils.APPLICATION_JSON, rSocketStrategies);

        return  RSocketRequester.wrap(this.rSocket(),
                MimeTypeUtils.APPLICATION_JSON, rSocketStrategies);
    }
}

這裏,我們創建RSocket Client(消費者),並將其配置端口7000,使用TCP傳輸。注意,這是我們之前配置的服務器端口。
接下來,我們將定義一個RSocketRequester的實例,它是一個圍繞RSocket的包裝器。這個bean將幫助我們與RSocket服務器進行交互。
定義了這些bean配置之後,我們就有了一個基本的結構。

消費者Controller

@RestController
public class MarkDataRestController {
    private final RSocketRequester requester;

    public MarkDataRestController(RSocketRequester requester) {
        this.requester = requester;
    }

    /**
     *功能描述 Request/Response模式,目前通用的請求/響應模式
     * @author KL
     * @date 2019/5/27
     * @param stock
     * @return org.reactivestreams.Publisher<com.github.consumer.entity.MarketData>
     */
    @GetMapping("/current/{stock}")
    public Publisher<MarketData> current(@PathVariable String stock){
        return requester
                .route("currentMarketData")
                .data(new MarketDataRequest(stock))
                .retrieveMono(MarketData.class);
    }
    /**
     *功能描述 Request/Stream模式  ,一個簡單的請求返回多個響應.
     * Request/Stream模式是一個更復雜的交互模型,其中客戶機發送一個請求,但是在一段時間內從服務器獲得多個響應。
     * @author KL
     * @date 2019/5/27
     * @param stock
     * @return org.reactivestreams.Publisher<com.github.consumer.entity.MarketData>
     */
    @GetMapping(value = "/feed/{stock}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Publisher<MarketData> feed(@PathVariable("stock") String stock) {
        return requester.route("feedMarketData")
                .data(new MarketDataRequest(stock))
                .retrieveFlux(MarketData.class);
    }

    /**
     *功能描述 Fire And Forget模式,其實就是Client推送給Server端
     * @author KL
     * @date 2019/5/27
     * @param
     * @return org.reactivestreams.Publisher<java.lang.Void>
     */
    @GetMapping(value = "/collect")
    public Publisher<Void> collect() {
        return requester.route("collectMarketData")
                .data(getMarketData())
                .send();
    }

    private MarketData getMarketData() {
        return new MarketData("X", new Random().nextInt(10));
    }
}

總結

RSocket爲我們提供了一種新的服務通信思路,我們可以將RSocket應用到微服務框架中去,嘗試去替代Http的方案.
現在Springboot支持了,在過不久dubbo3.0也支持了,哈哈.學習吧.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章