Springboot2.2中的RSocket體驗
什麼是RSocket?
RSocket是一種二進制協議,用於TCP、websocket和Aeron等字節流傳輸。它通過異步消息在單個連接上傳遞,支持以下對稱交互模型:
- request/response (stream of 1)
- request/stream (finite stream of many)
- fire-and-forget (no response)
- 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也支持了,哈哈.學習吧.