添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在响应式的WebFlux出现以前,我们可以使用Spring MVC来编写Rest API,但是传统的基于Servlet的Web框架,在本质上都是阻塞和多线程的,每个连接都会使用一个线程,使用的是线程池中拉取的Worker线程,这里涉及到线程状态的切换,会耗时,且请求线程是阻塞的,直到Worker线程处理完为止。

Spring MVC编写Rest API

先回忆一下Spring MVC来编写Rest API的例子,这里使用《Spring实战(第五版)》中的示例代码:

@RestController
@RequestMapping(path="/design",                
                produces="application/json")
@CrossOrigin(origins="*")   
public class DesignTacoController {
  private TacoRepository tacoRepo;
  @Autowired
  EntityLinks entityLinks;
  public DesignTacoController(TacoRepository tacoRepo) {
    this.tacoRepo = tacoRepo;
  @GetMapping("/recent")
  public Iterable<Taco> recentTacos() {         
    PageRequest page = PageRequest.of(
            0, 12, Sort.by("createdAt").descending());
    return tacoRepo.findAll(page).getContent();
  @PostMapping(consumes="application/json")
  @ResponseStatus(HttpStatus.CREATED)
  public Taco postTaco(@RequestBody Taco taco) {
    return tacoRepo.save(taco);
  //end::postTaco[]
  @GetMapping("/{id}")
  public Taco tacoById(@PathVariable("id") Long id) {
    Optional<Taco> optTaco = tacoRepo.findById(id);
    if (optTaco.isPresent()) {
      return optTaco.get();
    return null;
 }

关于几个注解的说明:

@RestController

@CrossOrigin允许来自任何域的客户端消费该API

Spring WebFlux编写响应式Rest API

异步的Web框架能够以更少的线程获得更高的可扩展性,可以减少线程管理的开销。通过使用所谓的 事件轮询(event looping) 机制,这些框架能够用一个线程处理很多请求,这样每次连接的成本很低。
异步Web框架借助事件轮询机制能够以更少的线程处理更多的请求

Spring 5引入了一个非阻塞、异步的Web框架,该框架在很大程度上是基于 Reactor 项目的,能够解决Web应用和API中对更好的可扩展性的需求。
Spring 5通过名为WebFlux的新Web框架来支持反应式Web应用

在上图中,Spring MVC是建立在Java Servlet API之上,因此需要Servlet容器才(比如Tomcat)能执行。而WebFlux并不会绑定Servlet API,它构建在Reactive HTTP API之上(其实与Servlet API功能相同,只是采取了响应式的方式),因此WebFlux可以运行在任意非阻塞的Web容器中,包括Netty、Tomcat、Jetty等任意Servlet 3.1及以上的容器。

WebFlux的默认嵌入式服务器是Netty而不是Tomcat。Netty是一个异步、事件驱动的服务器,非常适合Spring WebFlux这样的响应式Web框架。

Spring WebFlux的控制器方法要接受和返回响应式类型,如Reactor中的Mono和Flux,而不是领域类型和集合。Spring WebFlux也能处理RxJava类型,如Observable、Single和Completable。

它应该成为完整的端到端反应式栈的一部分(为了最大化反应式Web框架的收益)

示例代码如下:

@RestController
@RequestMapping(path = "/design", produces = "application/json")
@CrossOrigin(origins = "*")
public class DesignTacoController {
  private TacoRepository tacoRepo;
  public DesignTacoController(TacoRepository tacoRepo) {
    this.tacoRepo = tacoRepo;
  @GetMapping("/recent")
  public Flux<Taco> recentTacos() {
    return tacoRepo.findAll().take(12);
  @PostMapping(consumes = "application/json")
  @ResponseStatus(HttpStatus.CREATED)
  public Mono<Taco> postTaco(@RequestBody Taco taco) {
    return tacoRepo.save(taco);
  @GetMapping("/{id}")
  public Mono<Taco> tacoById(@PathVariable("id") UUID id) {
    return tacoRepo.findById(id);
 尽管我们从repository得到了Flux<XXX>,但是直接返回后,由框架为我们调用subscribe(),所以在请求到来时,相应的方法会在数据真正从数据库取出之前就能立即返回。

Spring 5中的函数式模型编写响应式API

上面的代码仍然是使用的注解式WebFlux,虽然注解式很流行,但是仍有一些缺点。比如:

  • 所有基于注解的编程方式都会存在 注解该做什么 以及 注解如何做 之间的割裂
    注解本身定义了该做什么,但是具体如何做则是在框架代码的其他部分定义的,如果要进行自定义或者扩展,编程模型就会变得很麻烦,因为这样做需要修改注解之外的代码。
  • 代码调试比较麻烦,因为无法在注解上设置断点。

Spring 5中新的函数式编程模型像是一个库,而不是一个框架,能让我们在不使用注解的情况下,将请求映射到处理器代码中。

使用Spring的函数式编程模型在编写API会涉及4个主要的类型:

  • RequestPredicate :声明要处理的请求类型
  • RouterFunction : 声明如何将请求路由到处理器代码中
  • ServerRequest : 代表一个Http请求,包括对请求头和请求体的访问
  • ServerResponse : 代表一个Http响应,包括响应头和响应体信息

一个代码示例:

@Configuration
public class RouterFunctionConfig {
   @Autowired
   private TacaoRepository tacoRepo;
   @Bean
   public RouterFunction<?> routerFunction() {
     return route(GET("/design/taco"),this::recents)
          .andRoute(POST("/design"),this::postTaco); 
    public Mono<ServerResponse> recents(ServerRequest request) {
     return ServerResponse.ok()
          .body(tacoPepo.findAll().take(12),Taco.class);
    public Mono<ServerResponse> postTaco(ServerRequest request) {
     Mono<Taco> taco = request.bodyToMono(Taco.class);
     Mono<Taco> savedTaco = tacoPepo.save(taco);
     return ServerResponse.created(URI.created("http://localhost:8080/design/taco/" + 
            savedTaco.getId()))
            .body(savedTaco,Taco.class);

2020/7/7 补充:一个博主写的关于响应式事务和数据库的博文: https://www.jdon.com/tags/39413