SpringBoot中的响应式web应用详解

简介

在Spring 5中,Spring MVC引入了webFlux的概念,webFlux的底层是基于reactor-netty来的,而reactor-netty又使用了Reactor库。

本文将会介绍在Spring Boot中reactive在WebFlux中的使用。

Reactive in Spring

前面我们讲到了,webFlux的基础是Reactor。 于是Spring Boot其实拥有了两套不同的web框架,第一套框架是基于传统的Servlet API和Spring MVC,第二套是基于最新的reactive框架,包括 Spring WebFlux 和Spring Data的reactive repositories。

我们用上面的一张图可以清晰的看到两套体系的不同。

对于底层的数据源来说,MongoDB, Redis, 和 Cassandra 可以直接以reactive的方式支持Spring Data。而其他很多关系型数据库比如Postgres, Microsoft SQL Server, MySQL, H2 和 Google Spanner 则可以通过使用R2DBC 来实现对reactive的支持。

而Spring Cloud Stream甚至可以支持RabbitMQ和Kafka的reactive模型。

下面我们将会介绍一个具体的Spring Boot中使用Spring WebFlux的例子,希望大家能够喜欢。

注解方式使用WebFlux

要使用Spring WebFlux,我们需要添加如下的依赖:

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

只用注解的方式和普通的Spring MVC的方式很类似,我们可以使用@RestController表示是一个rest服务,可以使用 @GetMapping("/hello") 来表示一个get请求。

不同之处在于,我们请求的产生方式和返回值。

熟悉Reactor的朋友可能都知道,在Reactor中有两种产生序列的方式,一种是Flux一种是Mono,其中Flux表示1或者多,而Mono表示0或者1。

看一下我们的Controller该怎么写:

@RestController
public class WelcomeController {

 @GetMapping("/hello")
 public Mono<String> hello() {
  return Mono.just("www.flydean.com");
 }

 @GetMapping("/hellos")
 public Flux<String> getAll() {
  //使用lambda表达式
  return Flux.fromStream(Stream.of("www.flydean.com","flydean").map(String::toLowerCase));
 }

}

这个例子中,我们提供了两个get方法,第一个是hello,直接使用Mono.just返回一个Mono。

第二个方法是hellos,通过Flux的一系列操作,最后返回一个Flux对象。

有了Mono对象,我们怎么取出里面的数据呢?

public class WelcomeWebClient {
	private WebClient client = WebClient.create("http://localhost:8080");

	private final Mono<ClientResponse> result = client.get()
			.uri("/hello")
			.accept(MediaType.TEXT_PLAIN)
			.exchange();

	public String getResult() {
		return " result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
	}
}

我们通过WebClient来获取get的结果,通过exchange将其转换为ClientResponse。

然后提供了一个getResult方法从result中获取最终的返回结果。

这里,我们先调用FlatMap对ClientResponse进行转换,然后再调用block方法,产生一个新的subscription。

最后,我们看一下Spring Boot的启动类:

@Slf4j
@SpringBootApplication
public class Application {

 public static void main(String[] args) {
  SpringApplication.run(Application.class, args);

  WelcomeWebClient welcomeWebClient = new WelcomeWebClient();
  log.info("react result is {}",welcomeWebClient.getResult());
 }
}

编程方式使用webFlux

刚刚的注解方式其实跟我们常用的Spring MVC基本上是一样的。

接下来,我们看一下,如果是以编程的方式来编写上面的逻辑应该怎么处理。

首先,我们定义一个处理hello请求的处理器:

@Component
public class WelcomeHandler {

	public Mono<ServerResponse> hello(ServerRequest request) {
		return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
			.body(BodyInserters.fromValue("www.flydean.com!"));
	}
}

和普通的处理一样,我们需要返回一个Mono对象。

注意,这里是ServerRequest,因为WebFlux中没有Servlet。

有了处理器,我们需要写一个Router来配置路由:

@Configuration
public class WelcomeRouter {

	@Bean
	public RouterFunction<ServerResponse> route(WelcomeHandler welcomeHandler) {

		return RouterFunctions
			.route(RequestPredicates.GET("/hello").
					and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), welcomeHandler::hello);
	}
}

上面的代码将/hello和welcomeHandler::hello进行了绑定。

WelcomeWebClient和Application是和第一种方式是一样的。

public class WelcomeWebClient {
	private WebClient client = WebClient.create("http://localhost:8080");

	private Mono<ClientResponse> result = client.get()
			.uri("/hello")
			.accept(MediaType.TEXT_PLAIN)
			.exchange();

	public String getResult() {
		return " result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
	}
}
public class Application {

 public static void main(String[] args) {
  SpringApplication.run(Application.class, args);

  WelcomeWebClient welcomeWebClient = new WelcomeWebClient();
  log.info("react result is {}",welcomeWebClient.getResult());
 }
}

Spring WebFlux的测试

怎么对webFlux代码进行测试呢?

本质上是和WelcomeWebClient的实现是一样的,我们去请求对应的对象,然后检测其返回值,最后判断返回值是否我们所期待的内容。

如下所示:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WelcomeRouterTest {
 @Autowired
 private WebTestClient webTestClient;

 @Test
 public void testHello() {
  webTestClient
    .get().uri("/hello")
    .accept(MediaType.TEXT_PLAIN)
    .exchange()
    .expectStatus().isOk()
    .expectBody(String.class).isEqualTo("www.flydean.com!");
 }
}

总结

webFlux使用了Reactor作为底层的实现,和通常我们习惯的web请求方式是有很大不同的,但是通过我们的Spring框架,可以尽量保证原有的代码编写风格和习惯。

只需要在个别部分做微调。希望大家能够通过这个简单的例子,熟悉Reactive的基本编码实现。

本文的例子可以参考:springboot-reactive-web

到此这篇关于SpringBoot中的响应式web应用详解的文章就介绍到这了,更多相关SpringBoot响应式web应用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 运用springboot搭建并部署web项目的示例

    前言 一直以来都是用springmvc+mybatis进行后端接口开发工作,最近闲来无事,根据现有功能需求,用springboot+mybatis部署一套简单的web项目. 所用工具 IntelliJ IDEA 2018.1.4 JDK 1.8 apache-tomcat-8.0.50 所解决的问题 1.如何用idea创建springboot项目 2.如何进行 服务器.数据库.mybatis.视图解析器的配置 3.如何使用mybatis generator 自动生成代码 4.如何使用multip

  • springboot websocket简单入门示例

    之前做的需求都是客户端请求服务器响应,新需求是服务器主动推送信息到客户端.百度之后有流.长轮询.websoket等方式进行.但是目前更加推崇且合理的显然是websocket. 从springboot官网翻译了一些资料,再加上百度简单实现了springboot使用websocekt与客户端的双工通信. 1.首先搭建一个简单的springboot环境 <!-- Inherit defaults from Spring Boot --> <parent> <groupId>o

  • 解决spring-boot2.0.6中webflux无法获得请求IP的问题

    这几天在用 spring-boot 2 的 webflux 重构一个工程,写到了一个需要获得客户端请求 IP 的地方,发现写不下去了,在如下的 Handler(webflux 中 Handler 相当于 mvc 中的 Controller)中 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; im

  • SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送

    之前实现WebSocket基于STOMP的,觉得SpringBoot封装的太高,不怎么灵活,现在实现一个纯H5的,也大概了解webSocket在内部是怎么传输的. 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot中,我们还是需要导入WebSocket的包. 在pox.xml加上对springBoot对WebSocket的支持: <!-- webSocket --> <

  • springboot整合cxf发布webservice以及调用的方法

    webservice性能不高,但是现在好多公司还是在用,恰好今天在开发的时候对接项目组需要使用到webservice下面来说下简单的案例应用 首先老规矩:引入jar包 <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-spring-boot-starter-jaxws</artifactId> <version>3.1.11</version> &

  • SpringBoot中的响应式web应用详解

    简介 在Spring 5中,Spring MVC引入了webFlux的概念,webFlux的底层是基于reactor-netty来的,而reactor-netty又使用了Reactor库. 本文将会介绍在Spring Boot中reactive在WebFlux中的使用. Reactive in Spring 前面我们讲到了,webFlux的基础是Reactor. 于是Spring Boot其实拥有了两套不同的web框架,第一套框架是基于传统的Servlet API和Spring MVC,第二套是

  • SpringBoot中RabbitMQ集群的搭建详解

    目录 1. 两种模式 1.1 普通集群 1.2 镜像集群 1.3 节点类型 2. 搭建普通集群 2.1 预备知识 2.2 开始搭建 2.3 代码测试 2.4 反向测试 3. 搭建镜像集群 3.1 网页配置镜像队列 3.2 命令行配置镜像队列 4. 小结 单个的 RabbitMQ 肯定无法实现高可用,要想高可用,还得上集群. 今天松哥就来和大家聊一聊 RabbitMQ 集群的搭建. 1. 两种模式 说到集群,小伙伴们可能第一个问题是,如果我有一个 RabbitMQ 集群,那么是不是我的消息集群中的

  • Vue3 Reactive响应式原理逻辑详解

    目录 前言 一.怎么实现变量变化 二.怎么实现变量变化 三.将多个dep存储在Map中 四.将多个object的depsMap继续存储起来 五.核心 六.源码解析(TypeScript) 前言 本篇文章主要讲解vue响应式原理的逻辑,也就是vue怎么从最开始一步步推导出响应式的结构框架. 先从头构建一个简单函数推导出Vue3的Reactive原理,最后再进行源码的验证. 一.怎么实现变量变化 怎么实现变量变化,相关依赖的结果也跟着变化 当原本price=5变为price=20后total应该变为

  • flutter中使用流式布局示例详解

    目录 简介 Flow和FlowDelegate Flow的应用 总结 简介 我们在开发web应用的时候,有时候为了适应浏览器大小的调整,需要动态对页面的组件进行位置的调整.这时候就会用到flow layout,也就是流式布局. 同样的,在flutter中也有流式布局,这个流式布局的名字叫做Flow.事实上,在flutter中,Flow通常是和FlowDelegate一起使用的,FlowDelegate用来设置Flow子组件的大小和位置,通过使用FlowDelegate.paintChildre可

  • 基于rem的移动端响应式适配方案(详解)

    视口 在前一段时间,我曾经写过一篇关于viewport的文章.最近由于在接触移动端开发,对viewport有了新的理解.于是,打算重新写一篇文章,介绍移动端视口的相关概念. 关于这篇文章说到的所有知识,本质上离不开以下代码 <meta name="viewport" content="width=device-width, initial-scala=1, maximum-scale=1, minimum-scale=1, user-scalable=no"

  • springboot中使用redis的方法代码详解

    特别说明: 本文针对的是新版 spring boot 2.1.3,其 spring data 依赖为 spring-boot-starter-data-redis,且其默认连接池为 lettuce ​redis 作为一个高性能的内存数据库,如果不会用就太落伍了,之前在 node.js 中用过 redis,本篇记录如何将 redis 集成到 spring boot 中.提供 redis 操作类,和注解使用 redis 两种方式.主要内容如下: •docker 安装 redis •springboo

  • three.js响应式设计实例详解

    目录 1-canvas 的响应式布局 示例:三维插图 2-自适应设备分辨率 总结 源码地址:github.com/buglas/thre… 1-canvas 的响应式布局 canvas 画布的尺寸有两种: 像素尺寸,即canvas画布在高度和宽度上有多少个像素,默认是300*150 css 尺寸,即css 里的width和height 在web前端,dom元素的响应式布局一般是通过css 实现的. 而canvas 则并非如此,canvas 的响应式布局需要考虑其像素尺寸. 接下来,咱们就通过让c

  • springboot中rabbitmq实现消息可靠性机制详解

    1. 生产者模块通过publisher confirm机制实现消息可靠性 1.1 生产者模块导入rabbitmq相关依赖 <!--AMQP依赖,包含RabbitMQ--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-

  • 在springboot中使用拦截器的步骤详解

    目录 在springboot中使用拦截器 1. 定义拦截器 2. 使用JavaConfig注册拦截器 3. 定义控制器,测试拦截器 4. 总结 在springboot中使用拦截器 拦截器Interceptor,是SpringMVC中的核心内容,利用spring的AOP(Aspect Oriented Programming, 面向切面编程)特性,可以很方便的对用户的业务代码进行横向抽取,根据具体业务需求对应用功能进行增强.在SpringBoot中使用Interceptor,同时采用全注解开发,涉

  • bootstrap响应式表格实例详解

    Bootstrap 的响应式 CSS 能够自适应于台式机.平板电脑和手机,现在就bootstrap的响应式举一个例子: 如上图所示,要实现该表格在手机等移动端上只显示代号.名称.和价格,其他以查看详情的方式显示(也就是下图:) 首先,先实现在移动端能由左图到右图的转换: 代码如下: <meta charset="UTF-8"> <title></title> <!--引入bootstrap的css文件--> <link type=&

随机推荐