前言
WebFlux
是Spring5.0
推出的基于Reactor
响应式模型的MVC框架
,目前在国内相关的使用和资料比较少,本栏目主要分享一些使用过程中的经验,帮助大家入门并熟练使用这种响应式模型的编程方式。
开始
JDK我使用的是17,大家也可以升级下自己远古版本1.8了
引入依赖
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>annotationProcessor</scope>
</dependency>
</dependencies>
最简单的依赖就能启动项目
Hello World 环节
和Spring MVC并没有太大的差异,返回值用Mono Wrap一下
java
@RestController
public class TestController {
@GetMapping("/hello")
public Mono<String> hello() {
return Mono.just("hello world");
}
}
Run
启动项目 , 打印这条日志恭喜成功
Netty started on port 8080
shell
curl http://127.0.0.1:8080/hello
hello world
Why
SpringApplication.run(Application.class, args)
创造世界
java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 看这里,从classpath推导出springboot web环境
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
java
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
static WebApplicationType deduceFromClasspath() {
// 在这判断,如果是reactive环境就会启动响应式的容器
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
Mono与Flux
响应式中一个数据也能看为信号 Mono.just("hello world")
可以看为发了一个信号,而Flux
则是用来发送多个信号,比如Flux.just("1", "2", "3"),初学者可以简单粗暴的理解为List
类型。
通常来说响应式是需要我们进行消费的,不然一切都是白搭,比如
java
Mono.just("hello world")
.subscribe(s -> System.out.println(s));
但是Demo中我们并没有消费,因为webflux框架已经帮我们消费了
我们在自己写定时任务之类的操作中一定记得主动消费!!!
java
@Scheduled(fixedRateString = "5000")
public void scheduled() {
Mono.just("hello world")
.subscribe();
}
这只是简单的示例,实际中很可能是处理数据库数据、Redis数据等任务。
重要,前面的不看这个必须看!
Reactor模型是调度少量的线程来处理更多的任务,和我们以往的性能到底瓶颈就增加线程池的操作很不一样,所有在响应式的世界里禁止阻塞,这非常重要将严重影响你系统的吞吐量。
以前阻塞式编程的做法是,100个工人每个工人负责一个事情,忙不过来了就加到200个人。
响应式的处理是,只分配10个工人,每个工人通过一个总的调度来处理多个事情,比如1个人工人有10袋水泥,现在只需要把1袋搬上车就可以忙其他事情,等车运完这袋水泥回来再搬1袋,阻塞就相当于这个工人只能在这守着直到10袋水泥都搬运完。
所以求求你们千万不要在代码里.block();
除非你单独开一个线程池来处理。
Idea也会提醒你的