You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:45:28