Spring WebFlux返回Mono端点后幕后操作解析及手动触发方式咨询
问题背景
代码实现
@GetMapping("/test") public Mono<org.springframework.security.oauth2.jwt.Jwt> test() { Mono<org.springframework.security.oauth2.jwt.Jwt> mono = ReactiveSecurityContextHolder.getContext() .map(securityContext -> (org.springframework.security.oauth2.jwt.Jwt) securityContext.getAuthentication().getPrincipal()); // 原代码变量名笔误,修正为mono org.springframework.security.oauth2.jwt.Jwt jwtFromMono = mono .toFuture() .get(); System.out.println("jwt value is " + jwtFromMono); return mono ; }
执行现象
- 控制台输出:
jwt value is null
- HTTP响应返回有效Jwt数据:
{ "tokenValue": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlVzJhNVlVRXRoTFBYeTBVUWlXQTZudWtOQ2UtU0x2aU9IVlZ5RnJyVW9FIn0.eyJleHAiOjE2NzM2MzkwOTQsImlhdCI6MTY3MzYzODc5NCwianRpIjoiYTJjZTFmYWUtZWU1NS00MDc4LWE0NDctYzdkNDU3MWRhNWYwIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLTM3My05OWJhYy5kYnAuaW5uby50ZWNoL3JlYWxtcy90ZWNocGxhdCIsInN1YiI6Ijk5ZGZmZDliLWQ5OWEtNGM5Zi1hZWNhLTgxMThlMTYyOTU3MCIsInR5cCI6IkJlYXJlciIsImF6cCI6InBsYXQtZWNtLWNhbGxlci1jbGllbnQiLCJzZXNzaW9uX3N0YXRlIjoiNTQ4YzlhMTctZTdjYi00NzkxLTg5ZWUtMWU3OTU3ODQ2YWI3Iiwic2NvcGUiOiIiLCJzaWQiOiI1NDhjOWExNy1lN2NiLTQ3OTEtODllZS0xZTc5NTc4NDZhYjciLCJyb2xlcyI6WyJFQ01fVVNFUiJdfQ.Nfm-kqOp57bIuou8Qu0Gd4p06eUnbcKwEhxMGWGGqQN1Xh_czT2pNhqDQClsFVeyloIZeuKLCXvCJcK0-BrLqKwIWeQWX8lmmDEgdjwvPm9Uaypq2K1ur8OyzYTAocXRkL6_tcyP64th2m6xL5pVGeoqavdcDBR2e15_P8gHZaAzi8M6ke5V_uTNA6DNJrLAwMmHHjieWimBdFtxb5QFDtmfHWgyChYRQIvJVO74EKdXLv_XT_9hjByG2uQ5x4tEEtqZeWALlAMMzvcgHcA8llg5rHtvyGUl9Yv4d2oLoyHy22zvMO3BfxjpA4W19ps6vLHFLoUK9alcStuZlwSvPA", "issuedAt": "2023-01-13T19:39:54Z", "expiresAt": "2023-01-13T19:44:54Z" ... }
现象总结
- 手动调用
toFuture().get()时获取到null; - 返回Mono时能获取到安全上下文的有效Jwt数据。
提问
Spring WebFlux在端点方法返回Mono后执行了哪些幕后操作?能否在端点方法中手动触发这些操作?
回答
一、返回Mono后的幕后操作
1. 上下文绑定与传播
Spring WebFlux会将当前请求的SecurityContext(及其他请求上下文)绑定到Mono的订阅线程上。你直接调用get()是在端点方法的执行线程中同步阻塞取值,但此时SecurityContext尚未绑定到该线程,所以拿到null。而返回Mono后,WebFlux会在Reactor调度器的调度下,于合适时机订阅Mono,此时请求上下文已正确绑定到订阅线程,就能获取有效JWT。
2. 订阅触发与响应处理
WebFlux的请求处理链会主动订阅返回的Mono:
- 订阅触发后,
ReactiveSecurityContextHolder.getContext()才会实际执行,从绑定的上下文取出SecurityContext; - 获取JWT后,WebFlux通过消息转换器(如Jackson)将JWT序列化为JSON,写入HTTP响应体;
- 整个过程异步非阻塞,完全遵循Reactor响应式流规范,不会阻塞请求处理线程。
3. 异常与生命周期管理
WebFlux会处理Mono可能抛出的异常(如上下文不存在),转换为对应HTTP状态码返回;同时管理Mono生命周期,确保资源正确释放。
二、能否手动触发这些操作?
可以,但必须遵循响应式编程规范,不能用同步阻塞的get()方法,要通过Reactor API绑定上下文并订阅:
正确的手动触发方式
@GetMapping("/test") public Mono<org.springframework.security.oauth2.jwt.Jwt> test() { return ReactiveSecurityContextHolder.getContext() .map(securityContext -> (org.springframework.security.oauth2.jwt.Jwt) securityContext.getAuthentication().getPrincipal()) .doOnSuccess(jwt -> { // 在这里处理JWT,比如打印日志 System.out.println("jwt value is " + jwt); }); }
通过doOnSuccess操作符,在Mono成功获取值后执行自定义逻辑,既不破坏响应式流,又能拿到有效JWT。
为什么不能用toFuture().get()?
toFuture().get()是同步阻塞调用,会打破响应式非阻塞特性,且此时请求上下文未绑定到当前线程,无法获取SecurityContext。如果强行使用block()(同步阻塞API)手动取值,会引发线程饥饿问题,严重影响应用性能,因此强烈不推荐。
内容的提问来源于stack exchange,提问作者gstackoverflow
相关产品推荐
相关产品推荐

