Spring WebFlux是Spring框架的一个模块,用于构建反应式、异步和事件驱动的应用程序。它提供了一种基于Reactive Streams标准的编程模型,能够处理大量并发请求和高吞吐量,同时具有较低的资源消耗。
传统的Servlet API和Spring MVC是基于同步阻塞式编程模型的,而Spring WebFlux则是基于响应式编程模型的,相比较下有如下优势:
谈到Spring WebFlux就需要着重解释下响应式编程模型,响应式编程是一种面向数据流和变化传播的编程范式。它倡导使用异步数据流来构建事件驱动的、可扩展的应用程序。在响应式编程中,数据和事件以流的形式进行处理,并且整个系统会对这些流式数据进行监听和响应。主要优势如下:
假设我们需要实时获取多个城市的天气数据并展示给用户,这就涉及到了异步获取数据和实时推送数据给前端的需求。
在传统的同步编程模型中,如果我们采用每个城市一个线程的方式来获取天气数据,可能会因为网络IO等待而造成大量线程阻塞,浪费系统资源。而且随着城市数量的增多,线程管理和资源利用将变得更加困难。
通过采用响应式编程模型,我们可以将天气数据看作一个反应式流,通过订阅这个数据流,可以实时地获取各个城市的天气信息。当某个城市的天气数据发生变化时,系统能够及时地向订阅者发送新的数据,从而实现实时更新。
另外,由于天气数据的获取和推送是异步非阻塞的,不需要为每个城市的天气数据分配独立的线程,能够更高效地利用系统资源,提高系统的并发处理能力。
Spring WebFlux 框架由以下核心组件组成:
Handler是Spring WebFlux中用于处理请求的核心组件。它可以是一个函数式的处理器,也可以是一个注解式的控制器(类似于Spring MVC中的Controller)。当接收到一个HTTP请求时,WebFlux会根据路由规则把请求映射到对应的Handler上,然后由Handler来实际处理请求并生成响应。在函数式编程风格中,Handler通常是一个处理器函数,而在注解式编程中,Handler通常是一个带有@RequestMapping注解的控制器方法。
核心控制器DispatcherHandler等同于阻塞方式的DispatcherServlet,DispatcherHandler实现ApplicationContextAware,那么必然会调用setApplicationContext方法。
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
}
获取HandlerMapping,HandlerAdapter,HandlerResultHandler的所有实例
protected void initStrategies(ApplicationContext context) {
//获取HandlerMapping及其子类型的bean
//HandlerMapping根据请求request获取handler执行链
Map mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList mappings = new ArrayList<>(mappingBeans.values());
//排序
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
//获取HandlerAdapter及其子类型的bean
Map adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
//排序
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
//获取HandlerResultHandler及其子类型的bean
Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
Router用于定义URL路由规则,将请求映射到对应的Handler上。它负责根据请求的URL路径和HTTP方法找到对应的Handler,并将请求转发给该Handler进行处理。Router可以通过多种方式定义,包括函数式路由定义和注解式路由定义。在函数式编程风格中,我们可以使用Java 8的lambda表达式和RouterFunctions来定义路由规则;而在注解式编程中,我们可以使用类似@RequestMapping和@RestController这样的注解来定义路由规则。
RouterFunction是用于定义路由规则的主要接口,它可以将HTTP请求映射到对应的处理函数。通过RouterFunction,我们可以根据请求的URL路径和HTTP方法找到对应的Handler,并将请求转发给该Handler进行处理。
@Configuration
public class RouterConfig {
@Bean
public RouterFunction helloRouterFunction(HelloHandler helloHandler) {
return route(GET("/hello"), helloHandler::handleHello);
}
}
在这段示例代码中,我们首先通过@Configuration注解标记了RouterConfig类,使其成为Spring的配置类。然后,我们使用@Bean注解定义了一个名为helloRouterFunction的Bean,它返回一个RouterFunction
这里的route(GET("/hello"), helloHandler::handleHello)表示当收到GET请求且路径为"/hello"时,将请求转发给helloHandler的handleHello方法进行处理。这里使用了静态导入,使得可以直接调用GET方法,简化路由规则的定义。
@Component
public class HelloHandler {
public Mono handleHello(ServerRequest request) {
return ServerResponse.ok().bodyValue("Hello, WebFlux!");
}
}
在HelloHandler类中,我们通过@Component注解标记为Spring管理的组件,并编写了handleHello方法来处理请求。该方法返回一个Mono
WebHandler是处理请求和生成响应的抽象接口,它充当了请求和响应对象之间的桥梁。在WebFlux中,WebHandler接口定义了handle方法,用于处理ServerHttpRequest和ServerHttpResponse对象。它提供了一种统一的处理机制,使得不同类型的Handler可以与请求-响应生命周期进行交互。
首先你需要明确一点就是:WebFlux不是Spring MVC的替代方案,WebFlux并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性 。虽然WebFlux也可以被运行在Servlet容器上(需是Servlet 3.1+以上的容器),但是WebFlux
主要还是应用在异步非阻塞编程模型,而Spring MVC是同步阻塞的,如果你目前在Spring MVC框架中大量使用非同步方案,那么,WebFlux才是你想要的,否则,使用Spring MVC才是你的首选。
在微服务架构中,Spring MVC和WebFlux可以混合使用,比如已经提到的,对于那些IO密集型服务(如网关),我们就可以使用WebFlux来实现。
从上图中,可以一眼看出Spring MVC和Spring WebFlux的相同点和不同点:
pom.xml:
4.0.0
com.example
webflux-demo
1.0.0
org.springframework.boot
spring-boot-starter-parent
2.5.3
org.springframework.boot
spring-boot-starter-webflux
在上述配置中,我们使用了Spring Boot的起步依赖
spring-boot-starter-webflux来引入WebFlux相关的依赖。接下来,我们将创建一个简单的Controller并将其拆分到单独的类中。
首先,创建一个名为 HelloController 的类:
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.function.server.ServerRequest;
import reactor.core.publisher.Mono;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloController {
public RouterFunction route() {
return route(GET("/hello"), this::handleHello);
}
private Mono handleHello(ServerRequest request) {
return ServerResponse.ok().bodyValue("Hello, WebFlux!");
}
}
然后在主应用程序中注入HelloController:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
@SpringBootApplication
public class WebFluxIntegrationDemo {
public static void main(String[] args) {
SpringApplication.run(WebFluxIntegrationDemo.class, args);
}
@Bean
public RouterFunction monoRouterFunction(HelloController helloController) {
return helloController.route();
}
}
在这个示例中,我们通过@Bean注解将HelloController注入到主应用程序中,并且调用其route方法来定义路由规则。
关于pring WebFlux 很多很多,本文主要总结如下几点
优点:
缺点:
适用范围: