Spring Boot 2 快速教程:WebFlux处理流程(五)
WebFlux请求处理流程
下面是spring mvc的请求处理流程
具体步骤:
-
第一步:发起请求到前端控制器(DispatcherServlet)
-
第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
匹配条件包括:请求路径、请求方法、header信息等 -
第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
HandlerInterceptor是请求路径上的拦截器,需要自己实现这个接口以拦截请求,做一些对handler的前置和后置处理工作。 -
第四步:前端控制器调用处理器适配器去执行Handler
-
第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
-
第六步:Handler执行完成给适配器返回ModelAndView
-
第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
-
第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
-
第九步:视图解析器向前端控制器返回View
-
第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
-
第十一步:前端控制器向用户响应结果
图解:注解驱动请求的webflux请求处理流程
我们可以对比SpringMVC的请求流程图对比来看
我们可以看到,处理流程基本一样,有以下主要的点不同
- 处理核心
- WebFlux--
DispatcherHandler
- SpringMvc--
DispatcherServlet
- WebFlux--
- 返回值处理器
- WebFlux--
HandlerResultHandler
- SpringMvc--
HandlerMethodReturnValueHandler
- WebFlux--
- 内容协商配置器
- WebFlux--
RequestedContentTypeResolverBuilder
- SpringMvc--
ContentNegotiationConfigurer
- WebFlux--
还有很多就不一一例举了,想知道核心组件对比结果的同学,可以看下图。注意很多图上的组件名称相同,但是包的位置是不同的,所以大家要注意区分,不要弄混了。
Web MVC VS. WebFlux 核心组件对比
WebFlux 都有哪些核心组件
Spring WebFlux 包含多个核心组件,它们共同构成了完整的响应式 Web 应用框架。下面是一些主要的核心组件:
-
DispatcherHandler:这是 WebFlux 的中央调度器,类似于 Spring MVC 中的 DispatcherServlet。它负责发现和调度 HTTP 请求处理器(handlers),并处理请求映射、调用和结果处理。
-
HandlerMapping:这个接口用于将请求映射到对应的处理器(handler)。它在应用程序上下文中被检测到,并用于确定请求应该由哪个处理器处理。
-
HandlerAdapter:这个接口帮助 DispatcherHandler 调用任何类型的处理器,而不需要关心具体的调用方式。它为不同的处理器提供了调用策略。
-
HandlerResultHandler:这个接口处理处理器调用后的结果,并生成最终的响应。它负责将处理器的结果转换为客户端可以接收的格式。
-
WebFilter:WebFilter 接口定义了一组过滤器,这些过滤器可以对请求和响应进行预处理和后处理。
-
ServerWebExchange:这个类封装了 HTTP 请求和响应的所有信息,例如请求头、请求体、URI、参数等。
-
ServerHttpRequest 和 ServerHttpResponse:这两个类分别代表服务器接收的 HTTP 请求和发送的 HTTP 响应。
-
WebSession:用于管理特定客户端的会话信息。
-
Reactive Streams:WebFlux 基于 Reactive Streams 规范,使用非阻塞背压机制来处理数据流。
-
Reactor 库:作为 Spring 5 的反应式编程基础,Reactor 提供了非阻塞的编程模型和工具,包括 Flux 和 Mono 等反应式类型。
-
WebClient:这是 Spring 5 中引入的非阻塞、支持响应式流的 HTTP 客户端,用于与其它服务进行通信。
-
Spring Data Reactive:提供对响应式数据访问的支持,例如 Reactive Repositories。
-
Spring Security Reactive:提供对响应式安全访问控制的支持。
-
HttpHandler:定义了最低级别的反应式 HTTP 请求处理合同,作为不同运行时之间的共同基础。
-
ContextPathCompositeHandler:允许在不同的上下文路径上注册多个应用程序。
这些组件共同工作,为开发人员提供了一个强大且灵活的响应式 Web 应用开发平台。通过这些组件,开发者可以构建出能够高效处理大量并发请求的应用程序。下面针对这些组件,V 哥将一一详细介绍核心源码的实现过程,帮助兄弟们彻底理解。
1. DispatcherHandler
DispatcherHandler 是 Spring WebFlux 的核心组件,它的作用类似于 Spring MVC 中的 DispatcherServlet。它负责将传入的 HTTP 请求分发给相应的处理器(handler),并处理请求的映射、调用和结果处理。以下是对 DispatcherHandler 组件源码实现逻辑和步骤的详细分析:
初始化过程
-
ApplicationContextAware 实现:DispatcherHandler 实现了 ApplicationContextAware 接口,这意味着它可以访问到 Spring 应用上下文中的 Bean。
-
HandlerMapping、HandlerAdapter 和 HandlerResultHandler 的初始化:DispatcherHandler 在初始化时会查找 Spring 应用上下文中所有的 HandlerMapping、HandlerAdapter 和 HandlerResultHandler 并初始化它们。
protected void initStrategies(ApplicationContext context) {// ... 省略部分代码 ...this.handlerMappings = ...;this.handlerAdapters = ...;this.resultHandlers = ...;}
请求处理过程
-
获取 HandlerMappings:DispatcherHandler 会通过 handlerMappings 来查找能够处理当前请求的 HandlerMapping。
-
映射请求到 Handler:使用找到的 HandlerMapping 将请求映射到具体的处理器(可能是一个 @Controller 方法或者一个 RouterFunction)。
-
调用 Handler:一旦找到处理器,DispatcherHandler 会使用适当的 HandlerAdapter 来调用处理器。
-
处理结果:处理器的执行结果会被 HandlerResultHandler 处理,生成响应。
核心方法:handle
DispatcherHandler 的核心方法是 handle,它定义了请求处理的流程:
public Mono<Void> handle(ServerWebExchange exchange) {// 检查是否初始化了 handlerMappingsif (this.handlerMappings == null) {return createNotFoundError();}// 使用 handlerMappings 来查找 handlerreturn Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange)).next() // 获取第一个 handler.switchIfEmpty(createNotFoundError()) // 如果没有找到 handler,返回错误.flatMap(handler -> invokeHandler(exchange, handler)) // 调用 handler.flatMap(result -> handleResult(exchange, result)); // 处理结果
}
错误处理
- createNotFoundError:如果没有找到合适的处理器,DispatcherHandler 会创建一个表示 "Not Found" 的响应。
其他组件的协同工作
- HandlerMapping:负责将请求 URL 映射到具体的处理器。
- HandlerAdapter:负责调用具体的处理器,Spring WebFlux 支持多种类型的处理器,HandlerAdapter 使得 DispatcherHandler 无需关心具体的调用细节。
- HandlerResultHandler:负责处理处理器的返回值,并将其转换为 HTTP 响应。
DispatcherHandler 的设计使得它非常灵活,可以很容易地扩展新的 HandlerMapping、HandlerAdapter 或 HandlerResultHandler 来支持不同的处理器类型和返回类型。
以上就是 DispatcherHandler 组件的源码实现逻辑和步骤的分析。通过这种方式,Spring WebFlux 能够以非阻塞的方式处理 Web 请求,提高应用的性能和可伸缩性。
2. HandlerMapping
HandlerMapping 是 Spring WebFlux 中的一个接口,它定义了将请求映射到处理器(handler)的逻辑。HandlerMapping 的实现类负责根据请求的类型、URL 模式等信息来确定哪个具体的处理器应该处理当前的请求。以下是对 HandlerMapping 组件的源码实现逻辑和步骤的详细分析:
HandlerMapping 接口定义
HandlerMapping 接口定义了以下关键方法:
public interface HandlerMapping {Mono<Object> getHandler(ServerWebExchange exchange);void afterPropertiesSet();
}
- getHandler:根据给定的 ServerWebExchange 对象,返回一个 Mono 对象,该 Mono 完成时包含请求的处理器。
- afterPropertiesSet:在所有属性都设置之后调用,允许 HandlerMapping 实现进行初始化。
主要实现类
Spring WebFlux 提供了几个 HandlerMapping 的实现类,主要包括:
-
RequestMappingHandlerMapping:处理基于注解的映射,例如 @RequestMapping、@GetMapping 等。
-
RouterFunctionMapping:处理基于 RouterFunction 的函数式路由。
-
SimpleUrlHandlerMapping:处理简单的 URL 到对象的映射。
RequestMappingHandlerMapping 源码分析
RequestMappingHandlerMapping 是最常用的 HandlerMapping 实现之一,下面是它的一些关键实现逻辑:
-
注册和解析:在初始化时,RequestMappingHandlerMapping 会扫描所有的 beans,查找带有 @RequestMapping 注解的方法,并注册这些方法作为请求的处理器。
-
映射处理:RequestMappingHandlerMapping 使用 Pattern 对象来存储和匹配 URL 模式。
-
getHandler 方法实现:
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {String lookupPath = getPath(exchange);return getHandlerInternal(exchange).filter(h -> matchesRoute(lookupPath, h)).switchIfEmpty(Mono.defer(() -> getBestMatchingHandler(lookupPath, exchange)));
}
- getPath:从 ServerWebExchange 中提取请求路径。
- getHandlerInternal:返回一个包含所有注册处理器的 Mono。
- filter 和 matchesRoute:检查处理器是否与请求路径匹配。
- getBestMatchingHandler:如果没有找到精确匹配的处理器,尝试找到最佳匹配的处理器。
映射匹配逻辑
映射匹配逻辑通常涉及以下步骤:
-
路径匹配:检查请求的路径是否与注册的 URL 模式匹配。
-
请求方法匹配:如果 URL 模式匹配,进一步检查请求的方法(GET、POST 等)是否与处理器支持的方法匹配。
-
参数条件匹配:检查请求是否包含处理器所需的参数。
-
头信息匹配:检查请求头是否满足特定的条件。
-
消费和产生媒体类型匹配:检查请求的 Accept 头和 Content-Type 是否与处理器支持的媒体类型匹配。
性能优化
RequestMappingHandlerMapping 还实现了一些性能优化措施,例如缓存匹配的 URL 模式,以减少重复的模式匹配操作。
小结一下
HandlerMapping 组件是 Spring WebFlux 请求处理流程中的关键部分,它负责将进入的请求映射到正确的处理器。通过使用不同的 HandlerMapping 实现,Spring WebFlux 支持灵活的请求映射策略,以适应不同的应用场景。
3. HandlerAdapter
HandlerAdapter 接口在 Spring WebFlux 中扮演着至关重要的角色,它的作用是将 DispatcherHandler 找到的处理器(handler)适配到具体的执行逻辑上。HandlerAdapter 使得 DispatcherHandler 无需关心具体的处理器类型,只需要通过 HandlerAdapter 来调用处理器即可。以下是对 HandlerAdapter 组件的源码实现逻辑和步骤的详细分析:
HandlerAdapter 接口定义
HandlerAdapter 接口定义了以下关键方法:
public interface HandlerAdapter {boolean supports(Object handler);Mono<Void> handle(ServerWebExchange exchange, Object handler, Object... args);
}
- supports:检查给定的处理器是否被当前 HandlerAdapter 支持。
- handle:调用处理器,并返回一个 Mono
<Void>
对象,表示异步的调用过程。
主要实现类
Spring WebFlux 提供了几个 HandlerAdapter 的实现类,主要包括:
-
RequestMappingHandlerAdapter:支持基于注解的控制器方法,如带有 @RequestMapping 注解的方法。
-
HttpHandlerAdapter:支持 HttpHandler 接口的处理器。
-
ControllerEndpointHandlerAdapter:支持 ControllerEndpoint 接口的处理器,通常用于 WebFlux 函数式编程。
-
RouterFunctionHandlerAdapter:支持 RouterFunction 接口,用于函数式路由。
RequestMappingHandlerAdapter 源码分析
RequestMappingHandlerAdapter 是最常用的 HandlerAdapter 实现之一,下面是它的一些关键实现逻辑:
- 支持性检查:supports 方法检查给定的处理器是否是 Controller 或者 RequestMapping 注解的方法。
@Override
public boolean supports(Object handler) {return (handler instanceof HandlerFunction) ||(handler instanceof Controller) ||AnnotationUtils.findAnnotation(handler.getClass(), RequestMapping.class) != null;
}
调用处理器:handle 方法调用处理器,并处理返回值。
@Overridepublic Mono<Void> handle(ServerWebExchange exchange, Object handler) {// 调用具体的处理器return ((HandlerFunction<ServerResponse>) handler).handle(exchange);}
调用处理器的逻辑
调用处理器的逻辑通常涉及以下步骤:
-
参数解析:解析请求中的参数,并将其转换为方法参数。
-
调用方法:调用处理器的方法,并将解析后的参数传递给方法。
-
处理返回值:处理方法的返回值,将其转换为响应。
-
异步处理:如果处理器返回的是 Mono 或 Flux,HandlerAdapter 需要处理这些异步结果。
错误处理
HandlerAdapter 还负责处理调用过程中的异常,将异常转换为合适的响应。
小结一下
HandlerAdapter 组件是 Spring WebFlux 请求处理流程中的关键部分,它解耦了 DispatcherHandler 和具体的处理器实现。通过使用不同的 HandlerAdapter 实现,Spring WebFlux 支持了多种类型的处理器,包括基于注解的控制器、函数式路由以及 HttpHandler 接口的实现。这种设计提高了框架的灵活性和可扩展性。
4. HandlerResultHandler
HandlerResultHandler 组件在 Spring WebFlux 中负责处理由 HandlerAdapter 调用处理器后返回的结果。它将这些结果转换为客户端可以接收的 HTTP 响应。以下是对 HandlerResultHandler 组件的源码实现逻辑和步骤的详细分析:
HandlerResultHandler 接口定义
HandlerResultHandler 接口定义了以下关键方法:
public interface HandlerResultHandler {boolean supports(HandlerResult result);Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result);
}
- supports:检查给定的 HandlerResult 是否被当前 HandlerResultHandler 支持。
- handleResult:处理 HandlerResult,生成响应并返回一个 Mono
<Void>
对象,表示异步的处理过程。
主要实现类
Spring WebFlux 提供了几个 HandlerResultHandler 的实现类,主要包括:
- ServerResponseResultHandler:处理 ServerResponse 类型的返回值。
- ResponseEntityResultHandler:处理 ResponseEntity 类型的返回值。
- ModelAndViewResultHandler:处理 ModelAndView 类型的返回值,通常用于视图渲染。
ServerResponseResultHandler 源码分析
ServerResponseResultHandler 是处理 ServerResponse 类型结果的 HandlerResultHandler 实现:
- 支持性检查:supports 方法检查 HandlerResult 是否包含 ServerResponse 对象。
@Override
public boolean supports(HandlerResult result) {return result.getReturnValue() instanceof ServerResponse;
}
- 处理结果:handleResult 方法处理 ServerResponse 对象,并生成响应。
@Overridepublic Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {ServerResponse response = (ServerResponse) result.getReturnValue();return response.writeTo(exchange, result.isCommitted());}
处理结果的逻辑
处理结果的逻辑通常涉及以下步骤:
-
获取返回值:从 HandlerResult 中获取处理器的返回值。
-
检查类型:根据返回值的类型,选择合适的处理逻辑。
-
生成响应:将返回值转换为 HTTP 响应。例如,ServerResponse 已经包含了响应的状态码、头信息和体。
-
异步处理:如果返回值是异步的(如 Mono 或 Flux),则需要处理这些异步结果。
-
写入响应:将生成的响应写入到 ServerWebExchange 中。
错误处理
HandlerResultHandler 还负责处理结果处理过程中的异常,将异常转换为合适的响应。
小结一下
HandlerResultHandler 组件是 Spring WebFlux 请求处理流程中的关键部分,它负责将处理器的返回值转换为 HTTP 响应。通过使用不同的 HandlerResultHandler 实现,Spring WebFlux 支持了多种返回值类型,包括 ServerResponse、ResponseEntity 和 ModelAndView。这种设计提高了框架的灵活性和可扩展性,允许开发者以不同的方式处理响应结果。
HandlerResultHandler 的实现通常需要考虑响应的异步特性,确保即使在异步流的情况下也能正确地生成和发送响应。此外,它还需要与 ServerWebExchange 紧密协作,以便访问和操作请求和响应的上下文信息。
5. WebFilter
WebFilter 接口是 Spring WebFlux 中用于拦截和处理 Web 请求和响应的组件。它允许开发者在请求到达具体的处理器之前或之后,对请求或响应进行额外的处理,例如日志记录、安全性检查、跨域处理等。以下是对 WebFilter 组件的源码实现逻辑和步骤的详细分析:
WebFilter 接口定义
WebFilter 接口定义了以下关键方法:
public interface WebFilter {Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
}
- filter:对给定的 ServerWebExchange 对象进行处理,并通过 WebFilterChain 调用链中的下一个 WebFilter 或最终的处理器。
过滤器链
在 Spring WebFlux 中,WebFilter 通常会被组织成一个过滤器链,每个 WebFilter 都可以决定是继续过滤请求还是将请求传递给链中的下一个 WebFilter。这种链式调用模式使得过滤器的执行顺序非常重要。
主要实现类
Spring WebFlux 提供了一些内置的 WebFilter 实现类,例如:
- ServerHttpSecurity:用于安全性检查。
- CorsFilter:用于处理跨源资源共享(CORS)。
- WebFilterChain:代表过滤器链的上下文,允许调用链中的下一个 WebFilter。
过滤器链的构建
过滤器链通常在应用程序的配置中构建,例如使用 WebFilter 接口的实现类:
@Configuration
public class WebFluxConfig {@Beanpublic WebFilter myCustomFilter() {return (exchange, chain) -> {// 在这里可以对请求进行预处理return chain.filter(exchange).subscriberContext(ctx -> ctx.put("customKey", "customValue"));};}
}
WebFilter 的实现逻辑
实现 WebFilter 接口的 filter 方法通常涉及以下步骤:
-
预处理:在调用 chain.filter(exchange) 之前,对 ServerWebExchange 进行任何必要的预处理,例如修改请求头、查询参数等。
-
调用链:使用 WebFilterChain 的 filter 方法将请求传递给链中的下一个 WebFilter。这通常会返回一个 Mono
<Void>
,表示异步的过滤过程。 -
后处理:在 chain.filter(exchange) 完成后,对 ServerWebExchange 进行任何必要的后处理,例如修改响应头、响应体等。
-
错误处理:处理在过滤过程中可能发生的异常,并决定是抛出新的错误、返回特定的响应或继续过滤链。
异步处理
由于 filter 方法返回的是 Mono<Void>
,WebFilter 的实现需要考虑异步处理。这意味着在过滤过程中,可以返回异步的响应,而不会阻塞整个请求的处理。
小结一下
WebFilter 组件是 Spring WebFlux 中用于拦截和处理 Web 请求和响应的强大工具。通过实现 WebFilter 接口并构建过滤器链,开发者可以灵活地对请求和响应进行预处理和后处理,以及实现各种横切关注点,如安全性、日志记录、CORS 处理等。这种设计提高了应用程序的模块性和可维护性,同时保持了非阻塞和异步的特性。
6. ServerWebExchange
ServerWebExchange 是 Spring WebFlux 中的一个核心组件,它封装了 HTTP 请求和响应的上下文信息,为 Web 服务器和应用程序之间提供了一个交互的接口。以下是对 ServerWebExchange 组件的源码实现逻辑和步骤的详细分析:
ServerWebExchange 接口定义
ServerWebExchange 接口定义了对 HTTP 请求和响应的访问和操作:
public interface ServerWebExchange {ServerHttpRequest getRequest();ServerHttpResponse getResponse();void beforeCommit();boolean isCommitted();void setCommitted(boolean committed);Context getContext();
}
- getRequest():返回当前的 ServerHttpRequest 对象,包含请求的详细信息。
- getResponse():返回当前的 ServerHttpResponse 对象,用于构造响应。
- beforeCommit():在响应提交之前调用,允许进行一些清理或准备操作。
- isCommitted():检查响应是否已经提交。
- setCommitted(boolean committed):设置响应是否提交的状态。
- getContext():返回与当前交换关联的 Context,用于存储和传递附加信息。
核心属性
ServerWebExchange 通常包含以下核心属性:
- request:ServerHttpRequest 对象,封装了 HTTP 请求的详细信息,如头信息、URI、方法等。
- response:ServerHttpResponse 对象,用于构造和发送 HTTP 响应。
- principal:可能包含当前请求的认证主体(Principal)。
- session:可能包含当前请求的会话信息。
- attributes:一个 Map,用于存储与请求相关的属性。
请求和响应的处理
ServerWebExchange 在请求和响应的处理中扮演着核心角色:
-
请求获取:通过 getRequest() 方法获取请求对象,访问请求的各种信息。
-
响应构造:通过 getResponse() 方法获取响应对象,构造响应的状态码、头信息和响应体。
-
上下文管理:使用 Context 对象存储和传递请求和响应过程中的附加信息。
-
提交管理:通过 beforeCommit()、isCommitted() 和 setCommitted() 方法管理响应的提交状态。
-
过滤器链:在 WebFilter 的实现中,ServerWebExchange 对象在过滤器链中传递,每个过滤器都可以访问和修改请求和响应。
异步处理
由于 WebFlux 是响应式的,ServerWebExchange 支持异步处理:
- 响应可以通过非阻塞的方式写入,例如使用 ServerHttpResponse 的异步方法。
- 请求和响应的处理可以在不同的线程或事件循环中进行。
小结一下
ServerWebExchange 是 Spring WebFlux 中处理 HTTP 请求和响应的核心组件。它提供了一个统一的接口来访问和操作请求和响应数据,同时支持异步非阻塞的处理方式。通过 ServerWebExchange,开发者可以在 Web 服务器和应用程序之间进行高效的数据交换和状态管理,实现高性能的响应式 Web 应用。
ServerWebExchange 的实现通常需要考虑响应式的编程模型,确保在处理请求和构造响应时不会阻塞事件循环,从而充分利用 WebFlux 的性能优势。此外,它还提供了丰富的上下文管理功能,使得在复杂的请求处理流程中,可以方便地存储和传递附加信息。
7. ServerHttpRequest和ServerHttpResponse
ServerHttpRequest 和 ServerHttpResponse 是 Spring WebFlux 中的两个核心接口,它们分别表示服务器接收的 HTTP 请求和发送的 HTTP 响应。以下是对这两个组件的源码实现逻辑和步骤的详细分析:
ServerHttpRequest 接口定义
ServerHttpRequest 接口定义了对 HTTP 请求的访问:
public interface ServerHttpRequest {URI getURI();HttpMethod getMethod();String getHeader(String headerName);MultiValueMap<String, String> getHeaders();DataBufferFactory bufferFactory();// 省略其他方法...
}
- getURI():返回请求的 URI。
- getMethod():返回 HTTP 方法(如 GET、POST 等)。
- getHeader(String headerName):根据名称获取请求头的值。
- getHeaders():返回包含所有请求头的 MultiValueMap。
- bufferFactory():返回用于创建数据缓冲区(DataBuffer)的工厂。
ServerHttpResponse 接口定义
ServerHttpResponse 接口定义了对 HTTP 响应的构造和发送:
public interface ServerHttpResponse {HttpStatusSeriesStatus.Series getStatusSeries();void setStatusCode(HttpStatus statusCode);String getHeader(String headerName);MultiValueMap<String, String> getHeaders();void setComplete();DataBufferFactory bufferFactory();Mono<Void> writeWith(Publisher<? extends DataBuffer> body);// 省略其他方法...
}
- getStatusSeries():返回响应的状态码系列(如 2xx、3xx 等)。
- setStatusCode(HttpStatus statusCode):设置 HTTP 状态码。
- getHeader(String headerName):根据名称获取响应头的值。
- getHeaders():返回包含所有响应头的 MultiValueMap。
- setComplete():标记响应为完成。
- writeWith(Publisher
<? extends DataBuffer> body)
:发送响应体。
请求和响应的处理
ServerHttpRequest 和 ServerHttpResponse 在处理 HTTP 请求和响应中扮演着核心角色:
-
请求信息获取:通过 ServerHttpRequest 的方法获取请求的 URI、方法、头信息等。
-
响应构造:使用 ServerHttpResponse 的方法设置状态码、头信息,并构造响应体。
-
数据缓冲区:通过 bufferFactory() 方法获取 DataBufferFactory,用于创建和管理数据缓冲区。
-
异步发送:ServerHttpResponse 的 writeWith(Publisher
<? extends DataBuffer> body)
方法支持异步发送响应体。 -
流式处理:支持以流式的方式读取请求体和写入响应体。
异步非阻塞
由于 WebFlux 是基于响应式编程模型的,ServerHttpRequest 和 ServerHttpResponse 支持异步非阻塞的操作:
- 请求体和响应体可以通过 Publisher
<DataBuffer>
形式异步读取和发送。 - 响应的发送不会阻塞事件循环。
小结一下
ServerHttpRequest 和 ServerHttpResponse 是 Spring WebFlux 中处理 HTTP 请求和响应的接口。它们提供了丰富的方法来访问请求信息、构造响应,并支持异步非阻塞的操作。通过这两个接口,开发者可以构建高性能、响应式的 Web 应用,充分利用现代硬件和软件架构的优势。
在实际应用中,开发者通常不需要直接实现这些接口,而是通过框架提供的实现类来操作请求和响应。这些实现类通常会与特定的运行时环境(如 Netty)集成,以提供高效的 I/O 操作。
8. WebSession
WebSession 组件在 Spring WebFlux 中用于表示和管理 Web 会话(session)。它提供了一种机制来存储和检索与特定用户会话相关的数据。以下是对 WebSession 组件的源码实现逻辑和步骤的详细分析:
WebSession 接口定义
WebSession 接口定义了 Web 会话的基本操作:
public interface WebSession {String getId();Mono<WebSession> save();void invalidate();Map<String, Object> getAttributes();<T> T getAttribute(String name);<T> void setAttribute(String name, T value);default <T> Mono<T> getAttributeOrDefault(String name, Supplier<? extends T> defaultValue);// 省略其他方法...
}
- getId():获取会话的唯一标识符。
- save():保存会话的更改。
- invalidate():使会话无效,相当于会话过期。
- getAttributes():获取会话的所有属性。
- getAttribute(String name):根据名称获取会话属性。
- setAttribute(String name, T value):设置会话属性。
WebSession 的实现逻辑
-
会话创建:WebSession 可以在请求处理过程中创建,通常与 ServerWebExchange 关联。
-
属性管理:会话属性存储在 getAttributes() 返回的 Map 中,允许存储和检索用户特定的信息。
-
异步保存:save() 方法异步保存会话更改,这可能涉及将更改写入底层存储。
-
会话失效:invalidate() 方法用于使会话无效,确保会话数据不再可用。
-
会话 ID 管理:每个 WebSession 实例都有一个唯一的 id,用于标识特定的用户会话。
-
默认值获取:getAttributeOrDefault() 方法提供了一种便捷的方式来获取属性值,如果属性不存在,则返回默认值。
会话的存储和检索
WebSession 的实现通常需要考虑以下方面:
- 存储机制:会话数据可以存储在不同的介质中,例如内存、数据库或分布式缓存。
- 并发处理:在多线程或异步环境中,需要确保会话数据的一致性。
- 会话超时:实现会话超时逻辑,自动使过期的会话无效。
会话的创建和绑定
在请求处理过程中,WebSession 可以被创建和绑定到 ServerWebExchange:
ServerWebExchange exchange = ...;
Mono<WebSession> sessionMono = exchange.getSession();
sessionMono.flatMap(session -> {// 使用会话return session.save();
});
小结一下
WebSession 组件是 Spring WebFlux 中用于管理 Web 会话的接口。它提供了一种灵活的方式来存储和检索与用户会话相关的数据,同时支持异步操作和多种存储选项。通过 WebSession,开发者可以轻松实现用户会话跟踪和管理,构建具有个性化用户体验的 Web 应用。
在实际应用中,开发者可以根据需要选择不同的会话存储实现,例如使用 Spring Session 项目提供的多种存储解决方案,包括 Redis、Hazelcast、JDBC 等。这些实现通常会处理会话的创建、保存、失效等逻辑,并与 WebSession 接口进行集成。
9. Reactive Streams
Reactive Streams 是一个规范,它定义了异步流处理的接口和行为,以便在不同的库和框架之间实现互操作性。Spring WebFlux 作为响应式编程的一部分,遵循 Reactive Streams 规范。以下是对 Reactive Streams 组件的源码实现逻辑和步骤的详细分析:
Reactive Streams 核心接口
Reactive Streams 规范定义了以下几个核心接口:
Publisher<T>
:发布者,表示可以产生数据的源头。Subscriber<T>
:订阅者,表示接收并处理数据的消费者。Subscription
:订阅关系,用于管理数据的请求和发送。Processor<T,R>
:处理器,是 Publisher 和 Subscriber 的结合体。
Publisher 接口
Publisher 接口是 Reactive Streams 的核心,它定义了如何将数据推送给 Subscriber:
public interface Publisher<T>
{
void subscribe(Subscriber<? super T>
s);
}
subscribe(`Subscriber<? super T> s`):允许 Subscriber 订阅 Publisher。
Subscriber 接口
Subscriber 接口定义了如何处理从 Publisher 接收到的数据:
public interface Subscriber<T> {void onSubscribe(Subscription s);void onNext(T t);void onError(Throwable t);void onComplete();
}
- onSubscribe(Subscription s):当 Subscriber 订阅 Publisher 后被调用,Subscription 用于控制数据流。
- onNext(T t):接收到新数据时调用。
- onError(Throwable t):发生错误时调用。
- onComplete():数据流结束时调用。
Subscription 接口
Subscription 接口用于管理 Subscriber 和 Publisher 之间的数据流:
public interface Subscription {void request(long n);void cancel();
}
- request(long n):请求 Publisher 发送指定数量的数据项。
- cancel():取消订阅,停止接收数据。
Processor 接口
Processor 是 Publisher 和 Subscriber 的结合体,可以接收数据并产生新的数据流:
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {// 继承自 Subscriber 和 Publisher 的方法
}
源码实现逻辑
- 数据流创建:使用 Publisher 创建数据流。
- 订阅机制:Subscriber 通过调用 Publisher 的 subscribe 方法订阅数据流。
- 数据请求:Subscriber 使用 Subscription 的 request 方法控制数据的接收速率。
- 数据推送:Publisher 根据 Subscriber 的请求发送数据项给 Subscriber。
- 错误和完成处理:Publisher 在发生错误或数据流结束时,分别调用 Subscriber 的 onError 或 onComplete 方法。
- 取消订阅:Subscriber 可以通过调用 Subscription 的 cancel 方法取消订阅。
步骤
- 初始化:创建 Publisher 和 Subscriber 对象。
- 订阅:Subscriber 调用 Publisher 的 subscribe 方法。
- 处理订阅:Publisher 调用 Subscriber 的 onSubscribe 方法,传入 Subscription 对象。
- 请求数据:Subscriber 使用 Subscription 请求数据。
- 发送数据:Publisher 根据请求发送数据给 Subscriber。
- 完成或错误:Publisher 在数据发送完毕后调用 onComplete,或在发生错误时调用 onError。
小结一下
Reactive Streams 规范提供了一种异步、非阻塞的数据处理模型,Spring WebFlux 通过实现这些接口,支持响应式编程。这种模型允许系统更有效地处理并发数据流,提高性能和可伸缩性。开发者可以利用 Reactive Streams 规范提供的接口和机制,构建高效、弹性的响应式应用程序。
10. Reactor 库
Reactor 是一个基于 Reactive Streams 规范的库,用于构建异步、非阻塞的响应式应用程序。它是 Spring WebFlux 的反应式编程基础。以下是对 Reactor 库组件的源码实现逻辑和步骤的详细分析:
Reactor 核心组件
Reactor 提供了以下核心组件:
- Flux:代表一个包含 0 到 N 个元素的响应式序列。
- Mono:代表一个包含 0 到 1 个元素的响应式序列。
- Scheduler:用于控制并发和执行异步操作的调度器。
Flux 和 Mono 的实现逻辑
-
数据流创建:通过静态方法(如 Flux.just(), Mono.just())或构造函数创建 Flux 或 Mono 实例。
-
操作符:Reactor 提供了丰富的操作符来处理数据流,例如 map、flatMap、filter 等。
-
订阅机制:通过 subscribe() 方法订阅数据流,并提供 Subscriber 来接收数据。
-
数据请求:使用 request() 方法控制数据的请求数量。
-
数据推送:数据通过 onNext() 方法推送给订阅者。
-
错误和完成处理:通过 onError() 和 onComplete() 方法处理数据流的错误和完成事件。
Scheduler 的实现逻辑
-
调度器创建:创建 Scheduler 实例,例如使用 Schedulers.parallel() 创建并行调度器。
-
任务调度:使用 schedule() 方法调度任务,返回 Mono 或 Flux。
-
并发控制:Scheduler 可以控制任务的并发执行,例如限制并发数量。
-
异步执行:任务在非阻塞的线程池中异步执行。
源码实现步骤
-
定义数据源:创建 Flux 或 Mono 实例作为数据源。
-
应用操作符:使用操作符对数据流进行转换、过滤或组合。
-
错误处理:使用 onErrorResume() 或 doOnError() 等操作符处理错误。
-
背压管理:使用 onBackpressureBuffer() 或 onBackpressureDrop() 等操作符处理背压。
-
订阅和消费:调用 subscribe() 方法订阅数据流,并提供 Subscriber 来消费数据。
-
调度任务:使用 Scheduler 调度异步任务。
-
资源清理:使用 dispose() 方法在不再需要时释放资源。
小结一下
Reactor 库通过 Flux、Mono 和 Scheduler 等组件,提供了一种强大的方式来构建响应式应用程序。它遵循 Reactive Streams 规范,支持异步非阻塞的数据流处理。Reactor 的操作符丰富,可以轻松实现复杂的数据处理逻辑。同时,它还提供了灵活的并发控制和调度机制,以适应不同的应用场景。
Reactor 的设计哲学是提供声明式的数据处理能力,让开发者能够以一种直观和灵活的方式构建响应式系统。通过 Reactor,开发者可以充分利用现代硬件的多核特性,提高应用程序的性能和可伸缩性。
11. WebClient
WebClient 是 Spring WebFlux 中用于发起 HTTP 请求的非阻塞响应式客户端。它允许你以声明式的方式构建请求并处理响应。以下是对 WebClient 组件的源码实现逻辑和步骤的详细分析:
WebClient 接口定义
WebClient 提供了发起请求的方法:
public interface WebClient {default URI uri() {return URI.create(this.baseUrl);}<T> Mono<T> getForObject(String url, Class<T> responseType, Object... uriVariables);<T> Flux<T> getForFlux(String url, Class<T> elementType, Object... uriVariables);// 其他 HTTP 方法的重载,例如 postForObject, putForObject 等
}
- uri():返回基础 URI。
- getForObject(String url, ...):发起 GET 请求并期望获取对象响应。
- getForFlux(String url, ...):发起 GET 请求并期望获取元素流响应。
WebClient.Builder 构建器
WebClient 的实例是通过 WebClient.Builder 构建的:
public final class WebClient.Builder {private final String baseUrl;public Builder(String baseUrl) {this.baseUrl = baseUrl;}public WebClient build() {return new ExchangeStrategiesDefaultWebClient(this);}// 其他配置选项,例如设置 ExchangeStrategies, ClientHttpRequestFactory 等
}
- baseUrl:定义客户端的基础 URL。
请求构建和发送
-
创建 WebClient 实例:使用 WebClient.Builder 创建并配置 WebClient 实例。
-
构建请求:使用 WebClient 的方法来添加请求头、查询参数、请求体等。
-
发起请求:调用 HTTP 方法对应的方法(如 getForObject、postForObject)来发起请求。
-
处理响应:响应以 Mono 或 Flux 的形式返回,可以进一步处理。
源码实现步骤
- 配置和创建:通过 WebClient.Builder 配置基础 URL 和其他选项,然后创建 WebClient 实例。
WebClient webClient = WebClient.builder().baseUrl("http://example.com").build();
构建请求:使用 WebClient 的方法链式构建请求。
Mono<Person> personMono = webClient.get().uri("/person/{id}", id).retrieve().bodyToMono(Person.class);
-
发起请求并获取响应:调用 retrieve() 方法并指定响应体转换的方式。
-
响应体转换:使用 bodyToMono 或 bodyToFlux 等方法将响应体转换为指定类型。
-
错误处理:使用 onErrorResume 或 onErrorMap 等操作符处理可能发生的错误。
-
订阅和消费:订阅响应体 Mono 或 Flux 并消费数据。
并发和异步处理
WebClient 支持并发和异步处理,允许以非阻塞的方式发起多个请求:
- 使用 Flux 可以处理多个响应。
- 可以使用 Scheduler 来控制并发级别。
小结一下
WebClient 是 Spring WebFlux 中一个强大且灵活的组件,用于构建非阻塞的响应式 HTTP 客户端。它允许以声明式的方式构建请求,并通过 Reactive Streams 规范支持异步数据处理。WebClient 的设计使得它非常适合在响应式应用程序中使用,可以充分利用现代异步编程的优势,提高应用程序的性能和可伸缩性。
开发者可以轻松地使用 WebClient 与外部服务进行通信,获取数据,并以响应式的方式处理这些数据。通过 WebClient,Spring WebFlux 应用程序可以无缝地集成到更大的响应式系统中。
12. Spring Data Reactive
Spring Data Reactive 是 Spring Data 项目的一部分,它提供了一组用于访问响应式数据存储的抽象。它允许以声明式和响应式的方式进行数据访问和操作,支持如 MongoDB、Redis、R2DBC(Reactive Relational Database Connectivity)等响应式数据库。以下是对 Spring Data Reactive 组件的源码实现逻辑和步骤的详细分析:
Spring Data Reactive 核心概念
- Reactive Repository:扩展了 Reactive Streams 规范,提供了异步的 CRUD 操作。
- ReactiveCrudRepository:基础接口,提供基本的 CRUD 操作。
- ReactiveMongoRepository、ReactiveRedisRepository 等:特定数据库的实现。
Reactive Repository 接口定义
public interface ReactiveCrudRepository<T, ID> extends ReactiveRepository<T, ID> {Mono<T> save(T entity);Flux<T> findAll();Mono<T> findById(ID id);Mono<Void> deleteById(ID id);// 其他方法...
}
- save(T entity):保存实体。
- findAll():查找所有记录。
- findById(ID id):通过 ID 查找记录。
- deleteById(ID id):通过 ID 删除记录。
响应式数据访问步骤
-
定义实体类:创建一个实体类,使用 JPA 注解或数据库特定的注解标记字段。
-
定义仓库接口:创建一个继承自 ReactiveCrudRepository 或特定数据库的 Repository 接口。
public interface MyEntityRepository extends ReactiveCrudRepository<MyEntity, Long> {// 可以添加自定义查询方法}
-
配置数据源:配置响应式数据源和客户端,例如配置 MongoDB 的 ReactiveMongoDatabase。
-
使用仓库:在服务层注入并使用仓库接口进行数据操作。
-
构建查询:使用仓库接口提供的方法或自定义查询方法构建查询。
-
异步处理:处理查询结果,使用 Mono 或 Flux 的异步特性。
源码实现逻辑
-
实体和仓库定义:定义数据实体和仓库接口。
-
Spring 应用上下文:Spring 应用上下文扫描仓库接口并创建代理实现。
-
执行查询:当调用仓库接口的方法时,代理将方法调用转换为数据库操作。
-
结果封装:查询结果封装在 Mono 或 Flux 中返回。
-
错误处理:处理可能发生的异常,将它们转换为合适的响应。
-
响应式流控制:使用 Reactive Streams 规范控制数据流。
响应式数据库操作示例
@Service
public class MyEntityService {private final MyEntityRepository repository;@Autowiredpublic MyEntityService(MyEntityRepository repository) {this.repository = repository;}public Mono<MyEntity> addMyEntity(MyEntity entity) {return repository.save(entity);}public Flux<MyEntity> getAllMyEntities() {return repository.findAll();}
}
小结一下
Spring Data Reactive 通过提供响应式仓库接口,简化了响应式数据访问的实现。它利用了 Reactive Streams 规范,允许以非阻塞的方式进行数据库操作,提高了应用程序的性能和可伸缩性。开发者可以轻松地定义仓库接口,并使用 Spring 提供的 CRUD 方法或自定义查询方法进行数据操作。
Spring Data Reactive 组件的设计允许它与现代响应式编程模型和框架(如 WebFlux)无缝集成,为构建响应式应用程序提供了强大的数据访问能力。通过使用 Spring Data Reactive,开发者可以构建高效、弹性的应用程序,同时保持代码的简洁性和可维护性。
13. Spring Security Reactive
Spring Security Reactive 是 Spring Security 的响应式扩展,它为响应式应用程序提供了安全和认证支持。以下是对 Spring Security Reactive 组件的源码实现逻辑和步骤的详细分析:
Spring Security Reactive 核心概念
- ServerSecurityContextRepository:用于在请求中存储和检索 SecurityContext。
- ReactiveSecurityContextHolder:管理 SecurityContext 的持有者。
- ServerSecurityConfigurer:用于配置安全上下文。
- ServerHttpSecurity:定义了响应式 HTTP 安全策略。
- ReactiveAuthenticationManager 和 ReactiveUserDetailsService:用于用户认证和用户详情服务。
ServerSecurityContextRepository 接口定义
public interface ServerSecurityContextRepository {Mono<Void> save(ServerSecurityContext context);Mono<ServerSecurityContext> load();void invalidate();
}
- save:保存 ServerSecurityContext。
- load:加载 ServerSecurityContext。
- invalidate:使 ServerSecurityContext 无效。
ServerHttpSecurity 配置
public class ServerHttpSecurity {public ServerHttpSecurity(ReactiveAuthenticationManager authentication) {// ...}public SecurityWebFilterChain build() {// ...}public ServerHttpSecurity authorizeExchange(Consumer<ServerAuthorizeExchangeSpec> configurer) {// ...}// 其他配置方法,例如 cors, csrf, formLogin, httpBasic 等
}
- authorizeExchange:配置授权策略。
- build:构建 SecurityWebFilterChain。
响应式认证和授权步骤
-
配置认证管理器:创建并配置 ReactiveAuthenticationManager。
-
配置用户服务:创建并配置 ReactiveUserDetailsService。
-
构建 ServerHttpSecurity:使用 ServerHttpSecurity 构建安全策略。
-
配置安全上下文存储:配置 ServerSecurityContextRepository。
-
注册 WebFilter:将 SecurityWebFilterChain 注册到 Web 过滤器链中。
-
处理认证和授权:在请求处理过程中,Spring Security Reactive 拦截请求并处理认证和授权。
源码实现逻辑
-
初始化:在应用程序启动时,Spring Security Reactive 初始化安全配置。
-
请求拦截:SecurityWebFilterChain 拦截请求并根据配置的安全策略进行处理。
-
认证:使用 ReactiveAuthenticationManager 进行用户认证。
-
授权:根据 ServerHttpSecurity 配置的授权规则,使用 ReactiveAccessDecisionManager 进行访问控制。
-
安全上下文:使用 ServerSecurityContextRepository 管理每个请求的安全上下文。
-
异常处理:处理安全相关的异常,如认证失败或访问拒绝。
-
响应:根据认证和授权的结果,构建响应并返回给客户端。
小结一下
Spring Security Reactive 为响应式应用程序提供了全面的安全支持。它基于 Spring Security 的核心概念,并通过响应式编程模型提供了异步、非阻塞的安全处理能力。通过 ServerHttpSecurity 的配置,开发者可以灵活地定义认证和授权策略,以满足不同应用程序的安全需求。
Spring Security Reactive 的设计允许它与 Spring WebFlux 无缝集成,为响应式 Web 应用程序提供强大的安全保障。通过使用 Spring Security Reactive,开发者可以构建安全、可靠且易于维护的响应式应用程序。
14. HttpHandler
HttpHandler 组件在 Spring WebFlux 中是一个用于处理 HTTP 请求的接口,它是响应式编程模型中最低层次的 HTTP 请求处理契约。HttpHandler 作为一个共同的接口,允许不同的运行时环境通过不同的实现来处理 HTTP 请求。以下是对 HttpHandler 组件的源码实现逻辑和步骤的详细分析:
HttpHandler 接口定义
HttpHandler 接口定义了一个 handle 方法,用于处理传入的 HTTP 请求并返回一个响应:
public interface HttpHandler {Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);
}
handle(ServerHttpRequest request, ServerHttpResponse response):处理给定的请求并构造响应。
核心职责
HttpHandler 的核心职责包括:
- 接收请求:接收 ServerHttpRequest 对象,该对象封装了 HTTP 请求的详细信息。
- 构造响应:根据请求信息构造 ServerHttpResponse 对象,设置状态码、响应头等。
- 返回结果:返回一个 Mono
<Void>
对象,表示异步的响应处理过程。
实现步骤
-
创建 HttpHandler 实例:实现 HttpHandler 接口或使用现有的实现。
-
处理请求:在 handle 方法中编写逻辑以处理请求,例如路由、认证、业务处理等。
-
构造响应:根据请求的处理结果构造响应,设置状态码、响应头和响应体。
-
返回 Mono
<Void>
:返回一个 Mono<Void>
,表示响应已经发送或将被发送。 -
错误处理:在 handle 方法中处理可能发生的异常,确保它们被适当地转换为响应。
示例实现
以下是一个简单的 HttpHandler 实现示例,它返回一个固定的响应:
public class SimpleHttpHandler implements HttpHandler {@Overridepublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {String body = "Hello, World!";response.getHeaders().add("Content-Type", "text/plain");return response.writeWith(Flux.just(DataBufferUtils.wrap(body)));}
}
小结一下
HttpHandler 组件是 Spring WebFlux 中用于处理 HTTP 请求的基础接口。它提供了一个简单而灵活的方式来处理 HTTP 请求和构造响应。通过实现 HttpHandler 接口,开发者可以控制整个请求处理流程,包括请求解析、业务逻辑处理和响应构建。
HttpHandler 的实现可以与其他 Spring WebFlux 组件(如 DispatcherHandler、HandlerMapping、HandlerAdapter 等)结合使用,以构建一个完整的响应式 Web 应用程序。这种低层次的接口为需要高度定制的 Web 应用程序提供了强大的灵活性。
15. ContextPathCompositeHandler
ContextPathCompositeHandler 是 Spring WebFlux 中的一个组件,它允许在同一服务器上将多个应用程序映射到不同的上下文路径(context paths)。这类似于在传统的 Servlet 容器中为每个 Web 应用程序配置不同的 URL 路径。
以下是对 ContextPathCompositeHandler 组件的源码实现逻辑和步骤的详细分析:
ContextPathCompositeHandler 接口定义
ContextPathCompositeHandler 实际上不是一个接口,而是 HandlerMapping 接口的一个实现,它组合了多个 Handler 对象,每个对象都关联一个上下文路径。
主要属性
- contextPaths:存储上下文路径和对应的 Handler 映射。
- pattern:用于匹配请求路径的正则表达式。
上下文路径映射
ContextPathCompositeHandler 维护了一个映射,将每个上下文路径映射到一个 Handler:
private final Map<String, HttpHandler> contextPaths = new ConcurrentHashMap<>();
添加应用程序
应用程序可以在初始化时通过 ContextPathCompositeHandler 的 addHandler 方法添加到映射中:
public void addHandler(String contextPath, HttpHandler handler) {this.contextPaths.put(contextPath, handler);// 更新正则表达式模式以匹配所有注册的上下文路径updatePattern();
}
处理请求
ContextPathCompositeHandler 通过 getHandler 方法来确定请求应该由哪个 Handler 处理:
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {String path = extractContextPath(exchange);return Mono.justOrEmpty(contextPaths.get(path)).map(HandlerAdapter::new).defaultIfEmpty(Mono.defer(() -> createNotFoundError(exchange)));
}
- extractContextPath:提取请求的上下文路径。
- getHandler:根据上下文路径从映射中获取对应的 Handler。
正则表达式模式
ContextPathCompositeHandler 使用正则表达式来匹配请求路径:
private void updatePattern() {// 构建匹配所有注册上下文路径的正则表达式String regex = contextPaths.keySet().stream().map(this::toRegex).collect(Collectors.joining("|", "^(", ")$"));this.compiledPattern = Pattern.compile(regex);
}
错误处理
如果没有找到匹配的上下文路径,ContextPathCompositeHandler 会创建一个表示 "Not Found" 的错误处理器:
private Mono<HandlerAdapter> createNotFoundError(ServerWebExchange exchange) {return Mono.just(new HandlerAdapter() {@Overridepublic boolean supports(Object handler) {return true;}@Overridepublic Mono<Void> handle(ServerWebExchange exchange, Object handler) {return ServerResponse.notFound().build().writeTo(exchange);}});
}
小结一下
ContextPathCompositeHandler 组件是 Spring WebFlux 中用于将多个应用程序映射到不同上下文路径的 HandlerMapping 实现。它通过维护一个上下文路径到 HttpHandler 的映射,允许每个应用程序处理其自己的请求路径。通过正则表达式匹配请求路径,并使用 HandlerAdapter 来适配和调用相应的处理器。
这种设计模式使得在单个服务器实例中部署和管理多个 WebFlux 应用程序变得简单和高效,每个应用程序都可以有自己的上下文路径,而 ContextPathCompositeHandler 负责将请求路由到正确的应用程序处理器。
相关文章:
Spring Boot 2 快速教程:WebFlux处理流程(五)
WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤: 第一步:发起请求到前端控制器(DispatcherServlet) 第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找) 匹配条件包括…...

Vue 鼠标事件合集,关于鼠标右键的处理方法(改写鼠标右键方法、自定义鼠标右键)
鼠标事件使用 mousedown"canvasDown($event)"按下事件合集 click 点击某个对象时触发 mousedown 鼠标按钮被按下时触发 mouseup 鼠标按钮被松开时触发 mouseleave 当鼠标指针移出元素时触发 dblclick 双击时触发 mousemove 鼠标移动时触发,…...

两种交换排序算法--冒泡,快速
目录 1.冒泡排序原理 2.快速排序原理 3.冒泡代码实现 4.快速排序代码实现 1.冒泡排序原理 冒泡排序(Bubble Sort)是一种简单的排序算法,基本思想是通过反复交换相邻的元素,直到整个序列有序。它的名字来源于较大的元素像气泡…...

语音交友app系统源码功能及技术研发流程剖析
语音交友App的核心功能包括语音聊天、语音房间、社交互动等,开发流程涵盖需求分析、技术选型、前后端开发、实时通信集成、测试优化、部署上线及运营维护。 一、语音交友App的大概功能 1. 语音聊天 一对一聊天:用户可与好友进行私密语音通话。 群组语音…...

零基础Vue入门7——状态管理Pinia
本节重点: pinia是什么pinia怎么用 pinia是什么 vue中组件间的数据传递: app.config.globalProperties:能够被应用内所有组件实例访问到的全局属性的对象props:父传子用provide:父传后代用 想象下有咩有哪些数据存储…...

Bash (Bourne-Again Shell)、Zsh (Z Shell)
文章目录 1. 历史背景2. 主要区别3. 功能对比自动补全插件和主题路径扩展提示符定制 4. 性能5. 使用场景6. 如何切换 Shell7. 总结 以下是 Bash 和 Zsh 之间的主要区别,列成表格方便对比: 特性BashZsh默认Shell大多数Linux发行版默认ShellmacOS默认She…...

Android studio 创建aar包给Unity使用
1、aar 是什么? 和 Jar有什么区别 aar 和 jar包 都是压缩包,可以使用压缩软件打开 jar包 用于封装 Java 类及其相关资源 aar 文件是专门为 Android 平台设计的 ,可以包含Android的专有内容,比如AndroidManifest.xml 文件 &#…...

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求
DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法,通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力,其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们如何通过纯强化学习来增强 LLM 解决复杂问题的能力,而无…...

图论常见算法
图论常见算法 算法prim算法Dijkstra算法 用途最小生成树(MST):最短路径:拓扑排序:关键路径: 算法用途适用条件时间复杂度Kruskal最小生成树无向图(稀疏图)O(E log E)Prim最小生成树无…...

MySQL三大日志详解
在MySQL数据库的运行过程中,三大关键日志——binlog、redo log和undo log,起着至关重要的作用。理解这三大日志,对于深入掌握MySQL的工作原理、数据恢复以及主从复制等操作有着极大的帮助。本文将详细剖析这三大日志的作用和工作机制。 Binl…...

【SQL 中的分组查询与联合查询详解】
文章目录 SQL 中的分组查询与联合查询详解 1. GROUP BY分组查询 1.1 语句格式1.2 示例说明 1.2.1 分别查询哥哥组和弟弟组的英语成绩总和1.2.2 查询哥哥组的所有成绩总和 2. 联合查询 2.1 内连接 2.1.1 语法格式2.1.2 执行过程 2.2 外连接 2.2.1 左外连接2.2.2 右外连接 2.3 …...

【实战篇】用 Cursor 独立开发并上线电商类 Android APP 全攻略
一、为啥要用 Cursor 开发电商类 Android APP 家人们,如今电商类 APP 随处可见,不管是买衣服、食品,还是电子产品,都能通过这些 APP 轻松搞定。要是能自己开发一款电商类 Android APP,那可太酷啦!但开发 APP 可不是一件容易的事,涉及到很多技术,像写代码、设计界面、处…...

quartus24.1版本子模块因时钟问题无法综合通过,FPGA过OOC问题复盘
因为只负责一个子模块,所以需要单独对该子模块进行综合和过OOC,这时候已经有一些加虚拟pin文件,敲命令让子模块能过OOC的方法。但这个方法的前提是先过综合,然后再敲命令让虚拟管脚命令成功,最终可以过OOC。 今天负责…...

零基础Vue入门6——Vue router
本节重点: 路由定义路由跳转 前面几节学习的都是单页面的功能(都在专栏里面https://blog.csdn.net/zhanggongzichu/category_12883540.html),涉及到项目研发都是有很多页面的,这里就需要用到路由(vue route…...

使用 Let‘s Encrypt 和 OpenResty 实现域名转发与 SSL 配置
在搭建网站或服务时,确保域名的安全性和正确的流量转发是非常重要的。本文将介绍如何使用 Let’s Encrypt 获取免费的 SSL 证书,并将其配置到 OpenResty 中,同时实现特定的域名转发规则。这不仅可以提升网站的安全性,还能优化流量…...

Lambda 表达式
一、Lambda 表达式简介 Lambda 表达式是一种简洁的函数式编程方式,用于实现只有一个方法的接口(例如函数式接口)。 基本语法 (parameters) -> expression (parameters) -> { statements; } 参数:可以有零个或多个参数。…...

TCN时间卷积神经网络多变量多步光伏功率预测(Matlab)
代码下载:TCN时间卷积神经网络多变量多步光伏功率预测(Matlab) TCN时间卷积神经网络多变量多步光伏功率预测 一、引言 1.1、研究背景和意义 随着全球能源危机的加剧和环保意识的提升,可再生能源,尤其是太阳能&…...

【Elasticsearch】 Composite Aggregation 详解
1.什么是 Composite Aggregation? Composite Aggregation 是 Elasticsearch 中的一种特殊聚合方式,适用于需要分页展示的聚合结果。它与传统的聚合方式不同,采用了基于游标的分页模型。这种聚合方式可以高效地处理多级聚合中的所有桶&#x…...

如何通过 Logstash 将数据采集到 Elasticsearch
作者:来自 Elastic Andre Luiz 将 Logstash 与 Elasticsearch 集成以实现高效的数据提取、索引和搜索的分步指南。 什么是 Logstash? Logstash 是一种广泛使用的 Elastic Stack 工具,用于实时处理大量日志数据。它充当高效的数据管道&#x…...

mysql的cpu使用率100%问题排查
背景 线上mysql服务器经常性出现cpu使用率100%的告警, 因此整理一下排查该问题的常规流程。 1. 确认CPU占用来源 检查系统进程 使用 top 或 htop 命令,确认是否是 mysqld 进程导致CPU满载:top -c -p $(pgrep mysqld)2. 实时分析MySQL活动 …...

centos虚拟机迁移没有ip的问题
故事背景,我们的centos虚拟机本来是好好的,但是拷贝到其他电脑上就不能分配ip,我个人觉得这个vmware他们软件应该搞定这个啊,因为这个问题是每次都会出现的。 网络选桥接 网络启动失败 service network restart Restarting netw…...

接入 deepseek 实现AI智能问诊
1. 准备工作 注册 DeepSeek 账号 前往 DeepSeek 官网 注册账号并获取 API Key。 创建 UniApp 项目 使用 HBuilderX 创建一个新的 UniApp 项目(选择 Vue3 或 Vue2 模板)。 安装依赖 如果需要在 UniApp 中使用 HTTP 请求,推荐使用 uni.requ…...

用AVFrame + AVPacket 完成accede编码和直接用ffmpeg命令行实现acc编码的对比
在使用 FFmpeg 进行 AAC 音频编码时,可以选择两种方式:通过编程接口(如 AVFrame 和 AVPacket)实现 AAC 编码,或者直接使用 FFmpeg 命令行工具。这两种方式各有特点,适用于不同的场景。以下是对两种方法的详细分析,包括它们的区别、优缺点以及适用场景。 一、通过 AVFram…...

计算机网络笔记再战——理解几个经典的协议6——TCP与UDP
目录 先说端口号 TCP 使用序号保证顺序性和应答来保证有效性 超时重传机制 TCP窗口机制 UDP 路由协议 协议分类:IGP和EGP 几个经典的路由算法 RIP OSPF 链路状态数据库(LSDB) LSA(Link State Advertisement࿰…...

【AI】在Ubuntu中使用docker对DeepSeek的部署与使用
这篇文章前言是我基于部署好的deepseek-r1:8b模型跑出来的 关于部署DeepSeek的前言与介绍 在当今快速发展的技术环境中,有效地利用机器学习工具来解决问题变得越来越重要。今天,我将引入一个名为DeepSeek 的工具,它作为一种强大的搜索引擎&a…...

openssl使用
openssl使用 提取密钥对 数字证书pfx包含公钥和私钥,而cer证书只包含公钥。提取需输入证书保护密码 openssl pkcs12 -in xxx.pfx -nocerts -nodes -out pare.key提取私钥 openssl rsa -in pare.key -out pri.key提取公钥 openssl rsa -in pare.key -pubout -ou…...

《语义捕捉全解析:从“我爱自然语言处理”到嵌入向量的全过程》
首先讲在前面,介绍一些背景 RAG(Retrieval-Augmented Generation,检索增强生成) 是一种结合了信息检索与语言生成模型的技术,通过从外部知识库中检索相关信息,并将其作为提示输入给大型语言模型ÿ…...

HIVE如何注册UDF函数
如果注册UDF函数的时候报了上面的错误,说明hdfs上传的路径不正确, 一定要用下面的命令 hadoop fs -put /tmp/hive/111.jar /user/hive/warehouse 一定要上传到上面路径,这样在创建函数时,引用下面的地址就可以创建成功...

VsCode创建VUE项目
1. 首先安装Node.js和npm 通过网盘分享的文件:vsCode和Node(本人电脑Win11安装) 链接: https://pan.baidu.com/s/151gBWTFZh9qIDS9XWMJVUA 提取码: 1234 它们是运行和构建Vue.js应用程序所必需的。 1.1 Node安装,点击下一步即可 …...

x64、aarch64、arm与RISC-V64:详解四种处理器架构
x64、aarch64、arm与RISC-V64:详解四种处理器架构 x64架构aarch64架构ARM架构RISC-V64架构总结与展望在计算机科学领域,处理器架构是构建计算机系统的基石,它决定了计算机如何执行指令、管理内存和处理数据。x64、aarch64、arm与RISC-V64是当前主流的四种处理器架构,它们在…...