问题记录

  1. 最后的结果Flux、Mono一定要作为方法返回值,因为响应式编程的异常信息保存在这些结果中(而不是在方法调用时抛出),所以这些结果必须作为方法返回值,否则Spring无法知道方法是否报错

常用api记录

  • 如果要操作数据,并返回一个Mono的时候,使用flatMap
  • 一般如果不操作数据,仅数据转换,使用map
  • 订阅者是由Spring框架去完成,我们(开发)写发布者代码
  • zipWith方法可以组合两个Mono/Flux,并返回新的Mono/Flux类型
  • take(x)适合取flux中前x个,而当flux就一个元素的适合,可以使用next()将flux转为mono
  • flatMapMany适合将Mono<数组/集合>转换为Flux
  • 当希望合并多个流操作的时候,可以使用Mono.zip/Flux.zip

    Mono.zip(memberLevelMono, giftCardMono, couponMono).map...

  • zipWith方法会同时请求待合并的两个Mono数据,而zipWhen方法则会阻塞等待第一个Mono数据到达在请求第二个Mono数据。

    aMono.zipWhen(...).zipWhen(...)
    第一个zipWhen方法会阻塞等待aMono数据返回再使用它的数据构造新的Mono,第二个zipWhen方法也会等待前面zipWhen构建的Mono数据返回再构建新Mono

  • 异常处理部分
    • onErrorReturn 的范围更大一些。onErrorReturn 返回一个静态值
    • onErrorResume 返回一个动态值,并且可以捕获,包装和重新抛出错误,例如作为自定义业务异常
  • ServerResponse.bodyValue和ServerResponse.body
    • 后者要求必须返回一个生产者(mono/flux),而bodyValue会自动包装成生产者,如下
    • ServerResponse.ok().bodyValue(Response.ok()) == ServerResponse.ok().body(Mono.just(Response.ok()),Response.class)
  • 路由式编程(webflux)

    RouterFunctions有俩个route的重载方法,所以以下两种写法都可

    • route(GET("/v1/oauth2/authorize").and(accept(MediaType.APPLICATION_JSON)).
      and(contentType(MediaType.APPLICATION_JSON)),saOAuth2ServerHandler::oauth2Authorize);
    • route().GET("/v1/oauth2/authorize", accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)), saOAuth2ServerHandler::oauth2Authorize);
  • 响应式请求下的rpc
    • 如果习惯了cloud的opengfeign的注解式调用.可以尝试下spring官方推荐的框架,reactivefeign(Playtika开源, 就是德州扑克的那家公司)
    • 地址:https://github.com/Playtika/feign-reactive, 目前看issue和tag还是很活跃的
1
2
3
4
5
6
7
8
9
10
/**
* 解决openFeign 调用服务报错:No qualifying bean of type ‘org.springframework.boot.autoconfigure.http.HttpMessage
* @param converters
* @return
*/
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
  • WebClient 支持负载均衡
1
2
3
4
5
6
7
8
9
10
Mono<Response> mono = webclientBuilder.build().get().uri("http://" + ServiceNameConstant.REPAST_SERVICE + "//category_sku/skus_sku_id?skuId=" + skuId).retrieve().bodyToMono(Response.class);
/**
* WebClient 支持负载均衡
* @return
*/
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}