WebFlux初尝试

前言

WebFluxSpring5.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也会提醒你的

相关推荐
西瓜er44 分钟前
JAVA:Spring Boot 集成 FFmpeg 实现多媒体处理
java·spring boot·ffmpeg
间彧1 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧1 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧1 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧1 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧1 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng2 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6013 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
Lisonseekpan3 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
我真的是大笨蛋3 小时前
Redis的String详解
java·数据库·spring boot·redis·spring·缓存